@percolatorct/sdk 0.5.1 → 1.0.0-beta.10
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/README.md +224 -23
- package/dist/abi/accounts.d.ts +7 -15
- package/dist/abi/errors.d.ts +11 -0
- package/dist/abi/instructions.d.ts +152 -31
- package/dist/config/program-ids.d.ts +1 -1
- package/dist/index.js +1527 -252
- package/dist/index.js.map +1 -1
- package/dist/math/trading.d.ts +116 -1
- package/dist/math/warmup.d.ts +50 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/lighthouse.d.ts +170 -0
- package/dist/solana/discovery.d.ts +253 -24
- package/dist/solana/index.d.ts +2 -0
- package/dist/solana/oracle.d.ts +10 -2
- package/dist/solana/pda.d.ts +0 -5
- package/dist/solana/rpc-pool.d.ts +347 -0
- package/dist/solana/slab.d.ts +41 -9
- package/dist/solana/stake.d.ts +2 -2
- package/dist/solana/static-markets.d.ts +86 -0
- package/dist/validation.d.ts +26 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -93,6 +93,7 @@ function concatBytes(...arrays) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
// src/abi/instructions.ts
|
|
96
|
+
var MAX_ORACLE_PRICE = 1000000000000n;
|
|
96
97
|
var IX_TAG = {
|
|
97
98
|
InitMarket: 0,
|
|
98
99
|
InitUser: 1,
|
|
@@ -116,16 +117,33 @@ var IX_TAG = {
|
|
|
116
117
|
ResolveMarket: 19,
|
|
117
118
|
WithdrawInsurance: 20,
|
|
118
119
|
AdminForceClose: 21,
|
|
120
|
+
// Tags 22-23: on-chain these are SetInsuranceWithdrawPolicy / WithdrawInsuranceLimited.
|
|
121
|
+
// Legacy aliases (UpdateRiskParams/RenounceAdmin) kept for backward compat.
|
|
122
|
+
SetInsuranceWithdrawPolicy: 22,
|
|
123
|
+
/** @deprecated Use SetInsuranceWithdrawPolicy */
|
|
119
124
|
UpdateRiskParams: 22,
|
|
125
|
+
WithdrawInsuranceLimited: 23,
|
|
126
|
+
/** @deprecated Use WithdrawInsuranceLimited */
|
|
120
127
|
RenounceAdmin: 23,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
128
|
+
// Tags 24–26: on-chain = QueryLpFees/ReclaimEmptyAccount/SettleAccount.
|
|
129
|
+
// Old insurance LP tags removed — those moved to percolator-stake.
|
|
130
|
+
QueryLpFees: 24,
|
|
131
|
+
ReclaimEmptyAccount: 25,
|
|
132
|
+
SettleAccount: 26,
|
|
133
|
+
// Tags 27-28: on-chain = DepositFeeCredits/ConvertReleasedPnl.
|
|
134
|
+
// Legacy aliases (PauseMarket/UnpauseMarket) kept — those instructions don't exist on-chain.
|
|
135
|
+
DepositFeeCredits: 27,
|
|
136
|
+
/** @deprecated No on-chain PauseMarket instruction */
|
|
124
137
|
PauseMarket: 27,
|
|
138
|
+
ConvertReleasedPnl: 28,
|
|
139
|
+
/** @deprecated No on-chain UnpauseMarket instruction */
|
|
125
140
|
UnpauseMarket: 28,
|
|
141
|
+
// Tags 29-30: on-chain = ResolvePermissionless/ForceCloseResolved.
|
|
142
|
+
ResolvePermissionless: 29,
|
|
143
|
+
/** @deprecated Use ResolvePermissionless */
|
|
126
144
|
AcceptAdmin: 29,
|
|
127
|
-
|
|
128
|
-
|
|
145
|
+
ForceCloseResolved: 30,
|
|
146
|
+
// Tag 31: gap (no decode arm on-chain)
|
|
129
147
|
SetPythOracle: 32,
|
|
130
148
|
UpdateMarkPrice: 33,
|
|
131
149
|
UpdateHyperpMark: 34,
|
|
@@ -199,8 +217,17 @@ var IX_TAG = {
|
|
|
199
217
|
/** PERC-8111: Set per-wallet position cap (admin only, cap_e6=0 disables). */
|
|
200
218
|
SetWalletCap: 70,
|
|
201
219
|
/** PERC-8110: Set OI imbalance hard-block threshold (admin only). */
|
|
202
|
-
SetOiImbalanceHardBlock: 71
|
|
220
|
+
SetOiImbalanceHardBlock: 71,
|
|
221
|
+
/** PERC-8270: Rescue orphan vault — recover tokens from a closed market's vault (admin). */
|
|
222
|
+
RescueOrphanVault: 72,
|
|
223
|
+
/** PERC-8270: Close orphan slab — reclaim rent from a slab whose market closed unexpectedly (admin). */
|
|
224
|
+
CloseOrphanSlab: 73,
|
|
225
|
+
/** PERC-SetDexPool: Pin admin-approved DEX pool address for a HYPERP market (admin). */
|
|
226
|
+
SetDexPool: 74,
|
|
227
|
+
/** CPI to the matcher program to initialize a matcher context account for an LP slot. Admin-only. */
|
|
228
|
+
InitMatcherCtx: 75
|
|
203
229
|
};
|
|
230
|
+
Object.freeze(IX_TAG);
|
|
204
231
|
var HEX_RE = /^[0-9a-fA-F]{64}$/;
|
|
205
232
|
function encodeFeedId(feedId) {
|
|
206
233
|
const hex = feedId.startsWith("0x") ? feedId.slice(2) : feedId;
|
|
@@ -211,11 +238,17 @@ function encodeFeedId(feedId) {
|
|
|
211
238
|
}
|
|
212
239
|
const bytes = new Uint8Array(32);
|
|
213
240
|
for (let i = 0; i < 64; i += 2) {
|
|
214
|
-
|
|
241
|
+
const byte = parseInt(hex.substring(i, i + 2), 16);
|
|
242
|
+
if (Number.isNaN(byte)) {
|
|
243
|
+
throw new Error(
|
|
244
|
+
`Failed to parse hex byte at position ${i}: "${hex.substring(i, i + 2)}"`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
bytes[i / 2] = byte;
|
|
215
248
|
}
|
|
216
249
|
return bytes;
|
|
217
250
|
}
|
|
218
|
-
var INIT_MARKET_DATA_LEN =
|
|
251
|
+
var INIT_MARKET_DATA_LEN = 352;
|
|
219
252
|
function encodeInitMarket(args) {
|
|
220
253
|
const data = concatBytes(
|
|
221
254
|
encU8(IX_TAG.InitMarket),
|
|
@@ -227,6 +260,11 @@ function encodeInitMarket(args) {
|
|
|
227
260
|
encU8(args.invert),
|
|
228
261
|
encU32(args.unitScale),
|
|
229
262
|
encU64(args.initialMarkPriceE6),
|
|
263
|
+
// 3 fields between header and RiskParams (immutable after init)
|
|
264
|
+
encU128(args.maxMaintenanceFeePerSlot ?? 0n),
|
|
265
|
+
encU128(args.maxInsuranceFloor ?? 0n),
|
|
266
|
+
encU64(args.minOraclePriceCap ?? 0n),
|
|
267
|
+
// RiskParams block (15 fields)
|
|
230
268
|
encU64(args.warmupPeriodSlots),
|
|
231
269
|
encU64(args.maintenanceMarginBps),
|
|
232
270
|
encU64(args.initialMarginBps),
|
|
@@ -239,7 +277,10 @@ function encodeInitMarket(args) {
|
|
|
239
277
|
encU64(args.liquidationFeeBps),
|
|
240
278
|
encU128(args.liquidationFeeCap),
|
|
241
279
|
encU64(args.liquidationBufferBps),
|
|
242
|
-
encU128(args.minLiquidationAbs)
|
|
280
|
+
encU128(args.minLiquidationAbs),
|
|
281
|
+
encU128(args.minInitialDeposit),
|
|
282
|
+
encU128(args.minNonzeroMmReq),
|
|
283
|
+
encU128(args.minNonzeroImReq)
|
|
243
284
|
);
|
|
244
285
|
if (data.length !== INIT_MARKET_DATA_LEN) {
|
|
245
286
|
throw new Error(
|
|
@@ -362,9 +403,16 @@ function encodeSetOracleAuthority(args) {
|
|
|
362
403
|
);
|
|
363
404
|
}
|
|
364
405
|
function encodePushOraclePrice(args) {
|
|
406
|
+
const price = typeof args.priceE6 === "string" ? BigInt(args.priceE6) : args.priceE6;
|
|
407
|
+
if (price === 0n) {
|
|
408
|
+
throw new Error("encodePushOraclePrice: price cannot be zero (division by zero in engine)");
|
|
409
|
+
}
|
|
410
|
+
if (price > MAX_ORACLE_PRICE) {
|
|
411
|
+
throw new Error(`encodePushOraclePrice: price exceeds maximum (${MAX_ORACLE_PRICE}), got ${price}`);
|
|
412
|
+
}
|
|
365
413
|
return concatBytes(
|
|
366
414
|
encU8(IX_TAG.PushOraclePrice),
|
|
367
|
-
encU64(
|
|
415
|
+
encU64(price),
|
|
368
416
|
encI64(args.timestamp)
|
|
369
417
|
);
|
|
370
418
|
}
|
|
@@ -405,15 +453,6 @@ function encodeRenounceAdmin() {
|
|
|
405
453
|
encU64(RENOUNCE_ADMIN_CONFIRMATION)
|
|
406
454
|
);
|
|
407
455
|
}
|
|
408
|
-
function encodeCreateInsuranceMint() {
|
|
409
|
-
return encU8(IX_TAG.CreateInsuranceMint);
|
|
410
|
-
}
|
|
411
|
-
function encodeDepositInsuranceLP(args) {
|
|
412
|
-
return concatBytes(encU8(IX_TAG.DepositInsuranceLP), encU64(args.amount));
|
|
413
|
-
}
|
|
414
|
-
function encodeWithdrawInsuranceLP(args) {
|
|
415
|
-
return concatBytes(encU8(IX_TAG.WithdrawInsuranceLP), encU64(args.lpAmount));
|
|
416
|
-
}
|
|
417
456
|
function encodeLpVaultWithdraw(args) {
|
|
418
457
|
return concatBytes(encU8(IX_TAG.LpVaultWithdraw), encU64(args.lpAmount));
|
|
419
458
|
}
|
|
@@ -441,17 +480,15 @@ function encodeSetPythOracle(args) {
|
|
|
441
480
|
}
|
|
442
481
|
var PYTH_RECEIVER_PROGRAM_ID = "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ";
|
|
443
482
|
async function derivePythPriceUpdateAccount(feedId, shardId = 0) {
|
|
444
|
-
const { PublicKey:
|
|
483
|
+
const { PublicKey: PublicKey15 } = await import("@solana/web3.js");
|
|
445
484
|
const shardBuf = new Uint8Array(2);
|
|
446
485
|
new DataView(shardBuf.buffer).setUint16(0, shardId, true);
|
|
447
|
-
const [pda] =
|
|
486
|
+
const [pda] = PublicKey15.findProgramAddressSync(
|
|
448
487
|
[shardBuf, feedId],
|
|
449
|
-
new
|
|
488
|
+
new PublicKey15(PYTH_RECEIVER_PROGRAM_ID)
|
|
450
489
|
);
|
|
451
490
|
return pda.toBase58();
|
|
452
491
|
}
|
|
453
|
-
IX_TAG["SetPythOracle"] = 32;
|
|
454
|
-
IX_TAG["UpdateMarkPrice"] = 33;
|
|
455
492
|
function encodeUpdateMarkPrice() {
|
|
456
493
|
return new Uint8Array([33]);
|
|
457
494
|
}
|
|
@@ -462,7 +499,7 @@ function computeEmaMarkPrice(markPrevE6, oracleE6, dtSlots, alphaE6 = MARK_PRICE
|
|
|
462
499
|
if (markPrevE6 === 0n || dtSlots === 0n) return oracleE6;
|
|
463
500
|
let oracleClamped = oracleE6;
|
|
464
501
|
if (capE2bps > 0n) {
|
|
465
|
-
const maxDelta = markPrevE6 * capE2bps * dtSlots
|
|
502
|
+
const maxDelta = markPrevE6 * capE2bps / 1000000n * dtSlots;
|
|
466
503
|
const lo = markPrevE6 > maxDelta ? markPrevE6 - maxDelta : 0n;
|
|
467
504
|
const hi = markPrevE6 + maxDelta;
|
|
468
505
|
if (oracleClamped < lo) oracleClamped = lo;
|
|
@@ -472,7 +509,6 @@ function computeEmaMarkPrice(markPrevE6, oracleE6, dtSlots, alphaE6 = MARK_PRICE
|
|
|
472
509
|
const oneMinusAlpha = 1000000n - effectiveAlpha;
|
|
473
510
|
return (oracleClamped * effectiveAlpha + markPrevE6 * oneMinusAlpha) / 1000000n;
|
|
474
511
|
}
|
|
475
|
-
IX_TAG["UpdateHyperpMark"] = 34;
|
|
476
512
|
function encodeUpdateHyperpMark() {
|
|
477
513
|
return new Uint8Array([34]);
|
|
478
514
|
}
|
|
@@ -616,6 +652,74 @@ function encodeTransferOwnershipCpi(args) {
|
|
|
616
652
|
function encodeSetWalletCap(args) {
|
|
617
653
|
return concatBytes(encU8(IX_TAG.SetWalletCap), encU64(args.capE6));
|
|
618
654
|
}
|
|
655
|
+
function encodeInitMatcherCtx(args) {
|
|
656
|
+
return concatBytes(
|
|
657
|
+
encU8(IX_TAG.InitMatcherCtx),
|
|
658
|
+
encU16(args.lpIdx),
|
|
659
|
+
encU8(args.kind),
|
|
660
|
+
encU32(args.tradingFeeBps),
|
|
661
|
+
encU32(args.baseSpreadBps),
|
|
662
|
+
encU32(args.maxTotalBps),
|
|
663
|
+
encU32(args.impactKBps),
|
|
664
|
+
encU128(args.liquidityNotionalE6),
|
|
665
|
+
encU128(args.maxFillAbs),
|
|
666
|
+
encU128(args.maxInventoryAbs),
|
|
667
|
+
encU16(args.feeToInsuranceBps),
|
|
668
|
+
encU16(args.skewSpreadMultBps)
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
function encodeSetInsuranceWithdrawPolicy(args) {
|
|
672
|
+
return concatBytes(encU8(IX_TAG.SetInsuranceWithdrawPolicy), encPubkey(args.authority), encU64(args.minWithdrawBase), encU16(args.maxWithdrawBps), encU64(args.cooldownSlots));
|
|
673
|
+
}
|
|
674
|
+
function encodeWithdrawInsuranceLimited(args) {
|
|
675
|
+
return concatBytes(encU8(IX_TAG.WithdrawInsuranceLimited), encU64(args.amount));
|
|
676
|
+
}
|
|
677
|
+
function encodeResolvePermissionless() {
|
|
678
|
+
return concatBytes(encU8(IX_TAG.ResolvePermissionless));
|
|
679
|
+
}
|
|
680
|
+
function encodeForceCloseResolved(args) {
|
|
681
|
+
return concatBytes(encU8(IX_TAG.ForceCloseResolved), encU16(args.userIdx));
|
|
682
|
+
}
|
|
683
|
+
function encodeCreateLpVault(args) {
|
|
684
|
+
const parts = [encU8(IX_TAG.CreateLpVault), encU64(args.feeShareBps)];
|
|
685
|
+
if (args.utilCurveEnabled !== void 0) {
|
|
686
|
+
parts.push(encU8(args.utilCurveEnabled ? 1 : 0));
|
|
687
|
+
}
|
|
688
|
+
return concatBytes(...parts);
|
|
689
|
+
}
|
|
690
|
+
function encodeLpVaultDeposit(args) {
|
|
691
|
+
return concatBytes(encU8(IX_TAG.LpVaultDeposit), encU64(args.amount));
|
|
692
|
+
}
|
|
693
|
+
function encodeLpVaultCrankFees() {
|
|
694
|
+
return concatBytes(encU8(IX_TAG.LpVaultCrankFees));
|
|
695
|
+
}
|
|
696
|
+
function encodeChallengeSettlement(args) {
|
|
697
|
+
return concatBytes(encU8(IX_TAG.ChallengeSettlement), encU64(args.proposedPriceE6));
|
|
698
|
+
}
|
|
699
|
+
function encodeResolveDispute(args) {
|
|
700
|
+
return concatBytes(encU8(IX_TAG.ResolveDispute), encU8(args.accept));
|
|
701
|
+
}
|
|
702
|
+
function encodeDepositLpCollateral(args) {
|
|
703
|
+
return concatBytes(encU8(IX_TAG.DepositLpCollateral), encU16(args.userIdx), encU64(args.lpAmount));
|
|
704
|
+
}
|
|
705
|
+
function encodeWithdrawLpCollateral(args) {
|
|
706
|
+
return concatBytes(encU8(IX_TAG.WithdrawLpCollateral), encU16(args.userIdx), encU64(args.lpAmount));
|
|
707
|
+
}
|
|
708
|
+
function encodeSetOffsetPair(args) {
|
|
709
|
+
return concatBytes(encU8(IX_TAG.SetOffsetPair), encU16(args.offsetBps));
|
|
710
|
+
}
|
|
711
|
+
function encodeAttestCrossMargin(args) {
|
|
712
|
+
return concatBytes(encU8(IX_TAG.AttestCrossMargin), encU16(args.userIdxA), encU16(args.userIdxB));
|
|
713
|
+
}
|
|
714
|
+
function encodeRescueOrphanVault() {
|
|
715
|
+
return concatBytes(encU8(IX_TAG.RescueOrphanVault));
|
|
716
|
+
}
|
|
717
|
+
function encodeCloseOrphanSlab() {
|
|
718
|
+
return concatBytes(encU8(IX_TAG.CloseOrphanSlab));
|
|
719
|
+
}
|
|
720
|
+
function encodeSetDexPool(args) {
|
|
721
|
+
return concatBytes(encU8(IX_TAG.SetDexPool), encPubkey(args.pool));
|
|
722
|
+
}
|
|
619
723
|
|
|
620
724
|
// src/abi/accounts.ts
|
|
621
725
|
import {
|
|
@@ -790,37 +894,6 @@ function buildAccountMetas(spec, keys) {
|
|
|
790
894
|
isWritable: s.writable
|
|
791
895
|
}));
|
|
792
896
|
}
|
|
793
|
-
var ACCOUNTS_CREATE_INSURANCE_MINT = [
|
|
794
|
-
{ name: "admin", signer: true, writable: false },
|
|
795
|
-
{ name: "slab", signer: false, writable: false },
|
|
796
|
-
{ name: "insLpMint", signer: false, writable: true },
|
|
797
|
-
{ name: "vaultAuthority", signer: false, writable: false },
|
|
798
|
-
{ name: "collateralMint", signer: false, writable: false },
|
|
799
|
-
{ name: "systemProgram", signer: false, writable: false },
|
|
800
|
-
{ name: "tokenProgram", signer: false, writable: false },
|
|
801
|
-
{ name: "rent", signer: false, writable: false },
|
|
802
|
-
{ name: "payer", signer: true, writable: true }
|
|
803
|
-
];
|
|
804
|
-
var ACCOUNTS_DEPOSIT_INSURANCE_LP = [
|
|
805
|
-
{ name: "depositor", signer: true, writable: false },
|
|
806
|
-
{ name: "slab", signer: false, writable: true },
|
|
807
|
-
{ name: "depositorAta", signer: false, writable: true },
|
|
808
|
-
{ name: "vault", signer: false, writable: true },
|
|
809
|
-
{ name: "tokenProgram", signer: false, writable: false },
|
|
810
|
-
{ name: "insLpMint", signer: false, writable: true },
|
|
811
|
-
{ name: "depositorLpAta", signer: false, writable: true },
|
|
812
|
-
{ name: "vaultAuthority", signer: false, writable: false }
|
|
813
|
-
];
|
|
814
|
-
var ACCOUNTS_WITHDRAW_INSURANCE_LP = [
|
|
815
|
-
{ name: "withdrawer", signer: true, writable: false },
|
|
816
|
-
{ name: "slab", signer: false, writable: true },
|
|
817
|
-
{ name: "withdrawerAta", signer: false, writable: true },
|
|
818
|
-
{ name: "vault", signer: false, writable: true },
|
|
819
|
-
{ name: "tokenProgram", signer: false, writable: false },
|
|
820
|
-
{ name: "insLpMint", signer: false, writable: true },
|
|
821
|
-
{ name: "withdrawerLpAta", signer: false, writable: true },
|
|
822
|
-
{ name: "vaultAuthority", signer: false, writable: false }
|
|
823
|
-
];
|
|
824
897
|
var ACCOUNTS_LP_VAULT_WITHDRAW = [
|
|
825
898
|
{ name: "withdrawer", signer: true, writable: false },
|
|
826
899
|
{ name: "slab", signer: false, writable: true },
|
|
@@ -942,6 +1015,13 @@ var ACCOUNTS_SET_WALLET_CAP = [
|
|
|
942
1015
|
{ name: "admin", signer: true, writable: false },
|
|
943
1016
|
{ name: "slab", signer: false, writable: true }
|
|
944
1017
|
];
|
|
1018
|
+
var ACCOUNTS_INIT_MATCHER_CTX = [
|
|
1019
|
+
{ name: "admin", signer: true, writable: false },
|
|
1020
|
+
{ name: "slab", signer: false, writable: false },
|
|
1021
|
+
{ name: "matcherCtx", signer: false, writable: true },
|
|
1022
|
+
{ name: "matcherProg", signer: false, writable: false },
|
|
1023
|
+
{ name: "lpPda", signer: false, writable: false }
|
|
1024
|
+
];
|
|
945
1025
|
var WELL_KNOWN = {
|
|
946
1026
|
tokenProgram: TOKEN_PROGRAM_ID,
|
|
947
1027
|
clock: SYSVAR_CLOCK_PUBKEY,
|
|
@@ -1226,11 +1306,24 @@ function getErrorName(code) {
|
|
|
1226
1306
|
function getErrorHint(code) {
|
|
1227
1307
|
return PERCOLATOR_ERRORS[code]?.hint;
|
|
1228
1308
|
}
|
|
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
|
+
}
|
|
1229
1321
|
var CUSTOM_ERROR_HEX_MAX_LEN = 8;
|
|
1230
1322
|
function parseErrorFromLogs(logs) {
|
|
1231
1323
|
if (!Array.isArray(logs)) {
|
|
1232
1324
|
return null;
|
|
1233
1325
|
}
|
|
1326
|
+
let insideLighthouse = false;
|
|
1234
1327
|
const re = new RegExp(
|
|
1235
1328
|
`custom program error: 0x([0-9a-fA-F]{1,${CUSTOM_ERROR_HEX_MAX_LEN}})(?![0-9a-fA-F])`,
|
|
1236
1329
|
"i"
|
|
@@ -1239,17 +1332,32 @@ function parseErrorFromLogs(logs) {
|
|
|
1239
1332
|
if (typeof log !== "string") {
|
|
1240
1333
|
continue;
|
|
1241
1334
|
}
|
|
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
|
+
}
|
|
1242
1340
|
const match = log.match(re);
|
|
1243
1341
|
if (match) {
|
|
1244
1342
|
const code = parseInt(match[1], 16);
|
|
1245
1343
|
if (!Number.isFinite(code) || code < 0 || code > 4294967295) {
|
|
1246
1344
|
continue;
|
|
1247
1345
|
}
|
|
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
|
+
}
|
|
1248
1355
|
const info = decodeError(code);
|
|
1249
1356
|
return {
|
|
1250
1357
|
code,
|
|
1251
1358
|
name: info?.name ?? `Unknown(${code})`,
|
|
1252
|
-
hint: info?.hint
|
|
1359
|
+
hint: info?.hint,
|
|
1360
|
+
source: info ? "percolator" : "unknown"
|
|
1253
1361
|
};
|
|
1254
1362
|
}
|
|
1255
1363
|
}
|
|
@@ -1416,6 +1524,8 @@ var V2_ENGINE_LP_MAX_ABS_OFF = 536;
|
|
|
1416
1524
|
var V2_ENGINE_LP_MAX_ABS_SWEEP_OFF = 552;
|
|
1417
1525
|
var V_ADL_ENGINE_OFF = 624;
|
|
1418
1526
|
var V_ADL_CONFIG_LEN = 520;
|
|
1527
|
+
var V_SETDEXPOOL_CONFIG_LEN = 544;
|
|
1528
|
+
var V_SETDEXPOOL_ENGINE_OFF = 648;
|
|
1419
1529
|
var V_ADL_ACCOUNT_SIZE = 312;
|
|
1420
1530
|
var V_ADL_ENGINE_PARAMS_OFF = 96;
|
|
1421
1531
|
var V_ADL_PARAMS_SIZE = 336;
|
|
@@ -1446,7 +1556,7 @@ var V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF = 952;
|
|
|
1446
1556
|
var V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF = 968;
|
|
1447
1557
|
var V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF = 976;
|
|
1448
1558
|
var V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF = 984;
|
|
1449
|
-
var V_ADL_ENGINE_BITMAP_OFF =
|
|
1559
|
+
var V_ADL_ENGINE_BITMAP_OFF = 1008;
|
|
1450
1560
|
var V_ADL_ACCT_WARMUP_STARTED_OFF = 64;
|
|
1451
1561
|
var V_ADL_ACCT_WARMUP_SLOPE_OFF = 72;
|
|
1452
1562
|
var V_ADL_ACCT_POSITION_SIZE_OFF = 88;
|
|
@@ -1457,6 +1567,47 @@ var V_ADL_ACCT_MATCHER_CONTEXT_OFF = 160;
|
|
|
1457
1567
|
var V_ADL_ACCT_OWNER_OFF = 192;
|
|
1458
1568
|
var V_ADL_ACCT_FEE_CREDITS_OFF = 224;
|
|
1459
1569
|
var V_ADL_ACCT_LAST_FEE_SLOT_OFF = 240;
|
|
1570
|
+
var V12_1_ENGINE_OFF = 648;
|
|
1571
|
+
var V12_1_ACCOUNT_SIZE = 320;
|
|
1572
|
+
var V12_1_ACCOUNT_SIZE_SBF = 280;
|
|
1573
|
+
var V12_1_ENGINE_BITMAP_OFF = 1016;
|
|
1574
|
+
var V12_1_ENGINE_PARAMS_OFF = 96;
|
|
1575
|
+
var V12_1_PARAMS_SIZE = 352;
|
|
1576
|
+
var V12_1_ENGINE_CURRENT_SLOT_OFF = 448;
|
|
1577
|
+
var V12_1_ENGINE_FUNDING_RATE_BPS_OFF = 456;
|
|
1578
|
+
var V12_1_ENGINE_LAST_CRANK_SLOT_OFF = 464;
|
|
1579
|
+
var V12_1_ENGINE_MAX_CRANK_STALENESS_OFF = 472;
|
|
1580
|
+
var V12_1_ENGINE_C_TOT_OFF = 480;
|
|
1581
|
+
var V12_1_ENGINE_PNL_POS_TOT_OFF = 496;
|
|
1582
|
+
var V12_1_ENGINE_LIQ_CURSOR_OFF = 528;
|
|
1583
|
+
var V12_1_ENGINE_GC_CURSOR_OFF = 530;
|
|
1584
|
+
var V12_1_ENGINE_LAST_SWEEP_START_OFF = 536;
|
|
1585
|
+
var V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF = 544;
|
|
1586
|
+
var V12_1_ENGINE_CRANK_CURSOR_OFF = 552;
|
|
1587
|
+
var V12_1_ENGINE_SWEEP_START_IDX_OFF = 554;
|
|
1588
|
+
var V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF = 560;
|
|
1589
|
+
var V12_1_ENGINE_TOTAL_OI_OFF = 816;
|
|
1590
|
+
var V12_1_ENGINE_LONG_OI_OFF = 832;
|
|
1591
|
+
var V12_1_ENGINE_SHORT_OI_OFF = 848;
|
|
1592
|
+
var V12_1_ENGINE_NET_LP_POS_OFF = 864;
|
|
1593
|
+
var V12_1_ENGINE_LP_SUM_ABS_OFF = 880;
|
|
1594
|
+
var V12_1_ENGINE_LP_MAX_ABS_OFF = 896;
|
|
1595
|
+
var V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF = 912;
|
|
1596
|
+
var V12_1_ENGINE_MARK_PRICE_OFF = 928;
|
|
1597
|
+
var V12_1_ENGINE_FUNDING_INDEX_OFF = 936;
|
|
1598
|
+
var V12_1_ENGINE_LAST_FUNDING_SLOT_OFF = 944;
|
|
1599
|
+
var V12_1_ENGINE_EMERGENCY_OI_MODE_OFF = 968;
|
|
1600
|
+
var V12_1_ENGINE_EMERGENCY_START_SLOT_OFF = 976;
|
|
1601
|
+
var V12_1_ENGINE_LAST_BREAKER_SLOT_OFF = 984;
|
|
1602
|
+
var V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF = 1008;
|
|
1603
|
+
var V12_1_ACCT_MATCHER_PROGRAM_OFF = 144;
|
|
1604
|
+
var V12_1_ACCT_MATCHER_CONTEXT_OFF = 176;
|
|
1605
|
+
var V12_1_ACCT_OWNER_OFF = 208;
|
|
1606
|
+
var V12_1_ACCT_FEE_CREDITS_OFF = 240;
|
|
1607
|
+
var V12_1_ACCT_LAST_FEE_SLOT_OFF = 256;
|
|
1608
|
+
var V12_1_ACCT_POSITION_SIZE_OFF = 88;
|
|
1609
|
+
var V12_1_ACCT_ENTRY_PRICE_OFF = -1;
|
|
1610
|
+
var V12_1_ACCT_FUNDING_INDEX_OFF = 288;
|
|
1460
1611
|
var V1M_ENGINE_OFF = 640;
|
|
1461
1612
|
var V1M_CONFIG_LEN = 536;
|
|
1462
1613
|
var V1M_ACCOUNT_SIZE = 248;
|
|
@@ -1494,15 +1645,7 @@ var V1M_ENGINE_EMERGENCY_START_SLOT_OFF = 688;
|
|
|
1494
1645
|
var V1M_ENGINE_LAST_BREAKER_SLOT_OFF = 696;
|
|
1495
1646
|
var V1M_ENGINE_BITMAP_OFF = 720;
|
|
1496
1647
|
var V1M2_ACCOUNT_SIZE = 312;
|
|
1497
|
-
var V1M2_ENGINE_BITMAP_OFF =
|
|
1498
|
-
var V1M2_ENGINE_CURRENT_SLOT_OFF = 408;
|
|
1499
|
-
var V1M2_ENGINE_FUNDING_INDEX_OFF = 416;
|
|
1500
|
-
var V1M2_ENGINE_LAST_FUNDING_SLOT_OFF = 432;
|
|
1501
|
-
var V1M2_ENGINE_FUNDING_RATE_BPS_OFF = 440;
|
|
1502
|
-
var V1M2_ENGINE_MARK_PRICE_OFF = 480;
|
|
1503
|
-
var V1M2_ENGINE_LAST_CRANK_SLOT_OFF = 504;
|
|
1504
|
-
var V1M2_ENGINE_MAX_CRANK_STALENESS_OFF = 512;
|
|
1505
|
-
var V1M2_RUNTIME_SHIFT = 32;
|
|
1648
|
+
var V1M2_ENGINE_BITMAP_OFF = 1008;
|
|
1506
1649
|
var ENGINE_OFF = V1_ENGINE_OFF;
|
|
1507
1650
|
var ENGINE_MARK_PRICE_OFF = V1_ENGINE_MARK_PRICE_OFF;
|
|
1508
1651
|
function computeSlabSize(engineOff, bitmapOff, accountSize, maxAccounts, postBitmap = 18) {
|
|
@@ -1521,6 +1664,9 @@ var V1D_SIZES = /* @__PURE__ */ new Map();
|
|
|
1521
1664
|
var V2_SIZES = /* @__PURE__ */ new Map();
|
|
1522
1665
|
var V1M_SIZES = /* @__PURE__ */ new Map();
|
|
1523
1666
|
var V_ADL_SIZES = /* @__PURE__ */ new Map();
|
|
1667
|
+
var V1M2_SIZES = /* @__PURE__ */ new Map();
|
|
1668
|
+
var V_SETDEXPOOL_SIZES = /* @__PURE__ */ new Map();
|
|
1669
|
+
var V12_1_SIZES = /* @__PURE__ */ new Map();
|
|
1524
1670
|
var V1D_SIZES_LEGACY = /* @__PURE__ */ new Map();
|
|
1525
1671
|
for (const n of TIERS) {
|
|
1526
1672
|
V0_SIZES.set(computeSlabSize(V0_ENGINE_OFF, V0_ENGINE_BITMAP_OFF, V0_ACCOUNT_SIZE, n), n);
|
|
@@ -1531,6 +1677,18 @@ for (const n of TIERS) {
|
|
|
1531
1677
|
V2_SIZES.set(computeSlabSize(V2_ENGINE_OFF, V2_ENGINE_BITMAP_OFF, V2_ACCOUNT_SIZE, n, 18), n);
|
|
1532
1678
|
V1M_SIZES.set(computeSlabSize(V1M_ENGINE_OFF, V1M_ENGINE_BITMAP_OFF, V1M_ACCOUNT_SIZE, n, 18), n);
|
|
1533
1679
|
V_ADL_SIZES.set(computeSlabSize(V_ADL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);
|
|
1680
|
+
V1M2_SIZES.set(computeSlabSize(V1M2_ENGINE_OFF, V1M2_ENGINE_BITMAP_OFF, V1M2_ACCOUNT_SIZE, n, 18), n);
|
|
1681
|
+
V_SETDEXPOOL_SIZES.set(computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18), n);
|
|
1682
|
+
V12_1_SIZES.set(computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18), n);
|
|
1683
|
+
}
|
|
1684
|
+
var V12_1_SBF_ACCOUNT_SIZE = 280;
|
|
1685
|
+
var V12_1_SBF_ENGINE_PREAMBLE = 558;
|
|
1686
|
+
for (const [, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
|
|
1687
|
+
const bitmapBytes = Math.ceil(n / 64) * 8;
|
|
1688
|
+
const preAccLen = V12_1_SBF_ENGINE_PREAMBLE + bitmapBytes + 18 + n * 2;
|
|
1689
|
+
const accountsOff = Math.ceil(preAccLen / 8) * 8;
|
|
1690
|
+
const total = V12_1_ENGINE_OFF + accountsOff + n * V12_1_SBF_ACCOUNT_SIZE;
|
|
1691
|
+
V12_1_SIZES.set(total, n);
|
|
1534
1692
|
}
|
|
1535
1693
|
var SLAB_TIERS_V2 = {
|
|
1536
1694
|
small: { maxAccounts: 256, dataSize: 65088, label: "Small", description: "256 slots (V2 BPF intermediate)" },
|
|
@@ -1826,41 +1984,68 @@ function buildLayoutV1M2(maxAccounts) {
|
|
|
1826
1984
|
accountsOff: engineOff + accountsOffRel,
|
|
1827
1985
|
engineInsuranceOff: 16,
|
|
1828
1986
|
engineParamsOff: V1M2_ENGINE_PARAMS_OFF,
|
|
1829
|
-
// 96 — expanded InsuranceFund
|
|
1830
|
-
paramsSize:
|
|
1831
|
-
// 336 — same as
|
|
1832
|
-
// Runtime fields:
|
|
1833
|
-
engineCurrentSlotOff:
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
//
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1987
|
+
// 96 — expanded InsuranceFund (same as V_ADL)
|
|
1988
|
+
paramsSize: V_ADL_PARAMS_SIZE,
|
|
1989
|
+
// 336 — same as V_ADL
|
|
1990
|
+
// Runtime fields: V1M2 engine struct is layout-identical to V_ADL — reuse V_ADL constants.
|
|
1991
|
+
engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,
|
|
1992
|
+
// 432
|
|
1993
|
+
engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,
|
|
1994
|
+
// 440
|
|
1995
|
+
engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
1996
|
+
// 456
|
|
1997
|
+
engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
1998
|
+
// 464
|
|
1999
|
+
engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,
|
|
2000
|
+
// 504
|
|
2001
|
+
engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
2002
|
+
// 528
|
|
2003
|
+
engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
2004
|
+
// 536
|
|
2005
|
+
engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,
|
|
2006
|
+
// 544
|
|
2007
|
+
engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,
|
|
2008
|
+
// 560
|
|
2009
|
+
engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,
|
|
2010
|
+
// 576
|
|
2011
|
+
engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,
|
|
2012
|
+
// 592
|
|
2013
|
+
enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,
|
|
2014
|
+
// 608
|
|
2015
|
+
engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,
|
|
2016
|
+
// 640
|
|
2017
|
+
engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,
|
|
2018
|
+
// 642
|
|
2019
|
+
engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,
|
|
2020
|
+
// 648
|
|
2021
|
+
engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
2022
|
+
// 656
|
|
2023
|
+
engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,
|
|
2024
|
+
// 664
|
|
2025
|
+
engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,
|
|
2026
|
+
// 666
|
|
2027
|
+
engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
2028
|
+
// 672
|
|
2029
|
+
engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
2030
|
+
// 680
|
|
2031
|
+
engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,
|
|
2032
|
+
// 904
|
|
2033
|
+
engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,
|
|
2034
|
+
// 920
|
|
2035
|
+
engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,
|
|
2036
|
+
// 936
|
|
2037
|
+
engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,
|
|
2038
|
+
// 952
|
|
2039
|
+
engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,
|
|
2040
|
+
// 968
|
|
2041
|
+
engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,
|
|
2042
|
+
// 976
|
|
2043
|
+
engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,
|
|
2044
|
+
// 984
|
|
1861
2045
|
engineBitmapOff: V1M2_ENGINE_BITMAP_OFF,
|
|
1862
2046
|
postBitmap: 18,
|
|
1863
|
-
acctOwnerOff:
|
|
2047
|
+
acctOwnerOff: V_ADL_ACCT_OWNER_OFF,
|
|
2048
|
+
// 192 — same shift as V_ADL (reserved_pnl u64→u128)
|
|
1864
2049
|
hasInsuranceIsolation: true,
|
|
1865
2050
|
engineInsuranceIsolatedOff: 48,
|
|
1866
2051
|
engineInsuranceIsolationBpsOff: 64
|
|
@@ -1950,7 +2135,7 @@ function buildLayoutVADL(maxAccounts) {
|
|
|
1950
2135
|
engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,
|
|
1951
2136
|
// 984
|
|
1952
2137
|
engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,
|
|
1953
|
-
//
|
|
2138
|
+
// 1008
|
|
1954
2139
|
postBitmap: 18,
|
|
1955
2140
|
acctOwnerOff: V_ADL_ACCT_OWNER_OFF,
|
|
1956
2141
|
// 192
|
|
@@ -1959,17 +2144,151 @@ function buildLayoutVADL(maxAccounts) {
|
|
|
1959
2144
|
engineInsuranceIsolationBpsOff: 64
|
|
1960
2145
|
};
|
|
1961
2146
|
}
|
|
2147
|
+
var SLAB_TIERS_V_SETDEXPOOL = {};
|
|
2148
|
+
for (const [label, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
|
|
2149
|
+
const size = computeSlabSize(V_SETDEXPOOL_ENGINE_OFF, V_ADL_ENGINE_BITMAP_OFF, V_ADL_ACCOUNT_SIZE, n, 18);
|
|
2150
|
+
SLAB_TIERS_V_SETDEXPOOL[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (V_SETDEXPOOL PERC-SetDexPool)` };
|
|
2151
|
+
}
|
|
2152
|
+
var SLAB_TIERS_V12_1 = {};
|
|
2153
|
+
for (const [label, n] of [["Micro", 64], ["Small", 256], ["Medium", 1024], ["Large", 4096]]) {
|
|
2154
|
+
const size = computeSlabSize(V12_1_ENGINE_OFF, V12_1_ENGINE_BITMAP_OFF, V12_1_ACCOUNT_SIZE, n, 18);
|
|
2155
|
+
SLAB_TIERS_V12_1[label.toLowerCase()] = { maxAccounts: n, dataSize: size, label, description: `${n} slots (v12.1)` };
|
|
2156
|
+
}
|
|
2157
|
+
function buildLayoutVSetDexPool(maxAccounts) {
|
|
2158
|
+
const engineOff = V_SETDEXPOOL_ENGINE_OFF;
|
|
2159
|
+
const bitmapOff = V_ADL_ENGINE_BITMAP_OFF;
|
|
2160
|
+
const accountSize = V_ADL_ACCOUNT_SIZE;
|
|
2161
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
2162
|
+
const bitmapBytes = bitmapWords * 8;
|
|
2163
|
+
const postBitmap = 18;
|
|
2164
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
2165
|
+
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
2166
|
+
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
2167
|
+
return {
|
|
2168
|
+
version: 1,
|
|
2169
|
+
headerLen: V1_HEADER_LEN,
|
|
2170
|
+
configOffset: V1_HEADER_LEN,
|
|
2171
|
+
configLen: V_SETDEXPOOL_CONFIG_LEN,
|
|
2172
|
+
// 544
|
|
2173
|
+
reservedOff: V1_RESERVED_OFF,
|
|
2174
|
+
engineOff,
|
|
2175
|
+
accountSize,
|
|
2176
|
+
maxAccounts,
|
|
2177
|
+
bitmapWords,
|
|
2178
|
+
accountsOff: engineOff + accountsOffRel,
|
|
2179
|
+
engineInsuranceOff: 16,
|
|
2180
|
+
engineParamsOff: V_ADL_ENGINE_PARAMS_OFF,
|
|
2181
|
+
paramsSize: V_ADL_PARAMS_SIZE,
|
|
2182
|
+
engineCurrentSlotOff: V_ADL_ENGINE_CURRENT_SLOT_OFF,
|
|
2183
|
+
engineFundingIndexOff: V_ADL_ENGINE_FUNDING_INDEX_OFF,
|
|
2184
|
+
engineLastFundingSlotOff: V_ADL_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
2185
|
+
engineFundingRateBpsOff: V_ADL_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
2186
|
+
engineMarkPriceOff: V_ADL_ENGINE_MARK_PRICE_OFF,
|
|
2187
|
+
engineLastCrankSlotOff: V_ADL_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
2188
|
+
engineMaxCrankStalenessOff: V_ADL_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
2189
|
+
engineTotalOiOff: V_ADL_ENGINE_TOTAL_OI_OFF,
|
|
2190
|
+
engineLongOiOff: V_ADL_ENGINE_LONG_OI_OFF,
|
|
2191
|
+
engineShortOiOff: V_ADL_ENGINE_SHORT_OI_OFF,
|
|
2192
|
+
engineCTotOff: V_ADL_ENGINE_C_TOT_OFF,
|
|
2193
|
+
enginePnlPosTotOff: V_ADL_ENGINE_PNL_POS_TOT_OFF,
|
|
2194
|
+
engineLiqCursorOff: V_ADL_ENGINE_LIQ_CURSOR_OFF,
|
|
2195
|
+
engineGcCursorOff: V_ADL_ENGINE_GC_CURSOR_OFF,
|
|
2196
|
+
engineLastSweepStartOff: V_ADL_ENGINE_LAST_SWEEP_START_OFF,
|
|
2197
|
+
engineLastSweepCompleteOff: V_ADL_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
2198
|
+
engineCrankCursorOff: V_ADL_ENGINE_CRANK_CURSOR_OFF,
|
|
2199
|
+
engineSweepStartIdxOff: V_ADL_ENGINE_SWEEP_START_IDX_OFF,
|
|
2200
|
+
engineLifetimeLiquidationsOff: V_ADL_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
2201
|
+
engineLifetimeForceClosesOff: V_ADL_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
2202
|
+
engineNetLpPosOff: V_ADL_ENGINE_NET_LP_POS_OFF,
|
|
2203
|
+
engineLpSumAbsOff: V_ADL_ENGINE_LP_SUM_ABS_OFF,
|
|
2204
|
+
engineLpMaxAbsOff: V_ADL_ENGINE_LP_MAX_ABS_OFF,
|
|
2205
|
+
engineLpMaxAbsSweepOff: V_ADL_ENGINE_LP_MAX_ABS_SWEEP_OFF,
|
|
2206
|
+
engineEmergencyOiModeOff: V_ADL_ENGINE_EMERGENCY_OI_MODE_OFF,
|
|
2207
|
+
engineEmergencyStartSlotOff: V_ADL_ENGINE_EMERGENCY_START_SLOT_OFF,
|
|
2208
|
+
engineLastBreakerSlotOff: V_ADL_ENGINE_LAST_BREAKER_SLOT_OFF,
|
|
2209
|
+
engineBitmapOff: V_ADL_ENGINE_BITMAP_OFF,
|
|
2210
|
+
postBitmap: 18,
|
|
2211
|
+
acctOwnerOff: V_ADL_ACCT_OWNER_OFF,
|
|
2212
|
+
hasInsuranceIsolation: true,
|
|
2213
|
+
engineInsuranceIsolatedOff: 48,
|
|
2214
|
+
engineInsuranceIsolationBpsOff: 64
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
function buildLayoutV12_1(maxAccounts, dataLen) {
|
|
2218
|
+
const engineOff = V12_1_ENGINE_OFF;
|
|
2219
|
+
const bitmapOff = V12_1_ENGINE_BITMAP_OFF;
|
|
2220
|
+
const hostSize = computeSlabSize(engineOff, bitmapOff, V12_1_ACCOUNT_SIZE, maxAccounts, 18);
|
|
2221
|
+
const isSbf = dataLen !== void 0 && dataLen !== hostSize;
|
|
2222
|
+
const accountSize = isSbf ? V12_1_ACCOUNT_SIZE_SBF : V12_1_ACCOUNT_SIZE;
|
|
2223
|
+
const bitmapWords = Math.ceil(maxAccounts / 64);
|
|
2224
|
+
const bitmapBytes = bitmapWords * 8;
|
|
2225
|
+
const postBitmap = 18;
|
|
2226
|
+
const nextFreeBytes = maxAccounts * 2;
|
|
2227
|
+
const preAccountsLen = bitmapOff + bitmapBytes + postBitmap + nextFreeBytes;
|
|
2228
|
+
const accountsOffRel = Math.ceil(preAccountsLen / 8) * 8;
|
|
2229
|
+
return {
|
|
2230
|
+
version: 1,
|
|
2231
|
+
// V12_1 upstream rebase uses 72-byte header (SlabHeader only, no V1 extension).
|
|
2232
|
+
// Empirically verified: USDC mint found at offset 72 on mainnet slab BVjPc6rd.
|
|
2233
|
+
headerLen: V0_HEADER_LEN,
|
|
2234
|
+
// 72 (not 104 — V12_1 removed the 32-byte header extension)
|
|
2235
|
+
configOffset: V0_HEADER_LEN,
|
|
2236
|
+
// 72
|
|
2237
|
+
configLen: 576,
|
|
2238
|
+
// 544 + 32 (dex_pool: [u8;32] added in V12_1)
|
|
2239
|
+
reservedOff: V1_RESERVED_OFF,
|
|
2240
|
+
engineOff,
|
|
2241
|
+
accountSize,
|
|
2242
|
+
maxAccounts,
|
|
2243
|
+
bitmapWords,
|
|
2244
|
+
accountsOff: engineOff + accountsOffRel,
|
|
2245
|
+
engineInsuranceOff: 16,
|
|
2246
|
+
engineParamsOff: V12_1_ENGINE_PARAMS_OFF,
|
|
2247
|
+
paramsSize: V12_1_PARAMS_SIZE,
|
|
2248
|
+
engineCurrentSlotOff: V12_1_ENGINE_CURRENT_SLOT_OFF,
|
|
2249
|
+
engineFundingIndexOff: V12_1_ENGINE_FUNDING_INDEX_OFF,
|
|
2250
|
+
engineLastFundingSlotOff: V12_1_ENGINE_LAST_FUNDING_SLOT_OFF,
|
|
2251
|
+
engineFundingRateBpsOff: V12_1_ENGINE_FUNDING_RATE_BPS_OFF,
|
|
2252
|
+
engineMarkPriceOff: V12_1_ENGINE_MARK_PRICE_OFF,
|
|
2253
|
+
engineLastCrankSlotOff: V12_1_ENGINE_LAST_CRANK_SLOT_OFF,
|
|
2254
|
+
engineMaxCrankStalenessOff: V12_1_ENGINE_MAX_CRANK_STALENESS_OFF,
|
|
2255
|
+
engineTotalOiOff: V12_1_ENGINE_TOTAL_OI_OFF,
|
|
2256
|
+
engineLongOiOff: V12_1_ENGINE_LONG_OI_OFF,
|
|
2257
|
+
engineShortOiOff: V12_1_ENGINE_SHORT_OI_OFF,
|
|
2258
|
+
engineCTotOff: V12_1_ENGINE_C_TOT_OFF,
|
|
2259
|
+
enginePnlPosTotOff: V12_1_ENGINE_PNL_POS_TOT_OFF,
|
|
2260
|
+
engineLiqCursorOff: V12_1_ENGINE_LIQ_CURSOR_OFF,
|
|
2261
|
+
engineGcCursorOff: V12_1_ENGINE_GC_CURSOR_OFF,
|
|
2262
|
+
engineLastSweepStartOff: V12_1_ENGINE_LAST_SWEEP_START_OFF,
|
|
2263
|
+
engineLastSweepCompleteOff: V12_1_ENGINE_LAST_SWEEP_COMPLETE_OFF,
|
|
2264
|
+
engineCrankCursorOff: V12_1_ENGINE_CRANK_CURSOR_OFF,
|
|
2265
|
+
engineSweepStartIdxOff: V12_1_ENGINE_SWEEP_START_IDX_OFF,
|
|
2266
|
+
engineLifetimeLiquidationsOff: V12_1_ENGINE_LIFETIME_LIQUIDATIONS_OFF,
|
|
2267
|
+
engineLifetimeForceClosesOff: V12_1_ENGINE_LIFETIME_FORCE_CLOSES_OFF,
|
|
2268
|
+
engineNetLpPosOff: V12_1_ENGINE_NET_LP_POS_OFF,
|
|
2269
|
+
engineLpSumAbsOff: V12_1_ENGINE_LP_SUM_ABS_OFF,
|
|
2270
|
+
engineLpMaxAbsOff: V12_1_ENGINE_LP_MAX_ABS_OFF,
|
|
2271
|
+
engineLpMaxAbsSweepOff: V12_1_ENGINE_LP_MAX_ABS_SWEEP_OFF,
|
|
2272
|
+
engineEmergencyOiModeOff: V12_1_ENGINE_EMERGENCY_OI_MODE_OFF,
|
|
2273
|
+
engineEmergencyStartSlotOff: V12_1_ENGINE_EMERGENCY_START_SLOT_OFF,
|
|
2274
|
+
engineLastBreakerSlotOff: V12_1_ENGINE_LAST_BREAKER_SLOT_OFF,
|
|
2275
|
+
engineBitmapOff: V12_1_ENGINE_BITMAP_OFF,
|
|
2276
|
+
postBitmap: 18,
|
|
2277
|
+
acctOwnerOff: V12_1_ACCT_OWNER_OFF,
|
|
2278
|
+
hasInsuranceIsolation: true,
|
|
2279
|
+
engineInsuranceIsolatedOff: 48,
|
|
2280
|
+
engineInsuranceIsolationBpsOff: 64
|
|
2281
|
+
};
|
|
2282
|
+
}
|
|
1962
2283
|
function detectSlabLayout(dataLen, data) {
|
|
2284
|
+
const v121n = V12_1_SIZES.get(dataLen);
|
|
2285
|
+
if (v121n !== void 0) return buildLayoutV12_1(v121n, dataLen);
|
|
2286
|
+
const vsdpn = V_SETDEXPOOL_SIZES.get(dataLen);
|
|
2287
|
+
if (vsdpn !== void 0) return buildLayoutVSetDexPool(vsdpn);
|
|
2288
|
+
const v1m2n = V1M2_SIZES.get(dataLen);
|
|
2289
|
+
if (v1m2n !== void 0) return buildLayoutV1M2(v1m2n);
|
|
1963
2290
|
const vadln = V_ADL_SIZES.get(dataLen);
|
|
1964
|
-
if (vadln !== void 0)
|
|
1965
|
-
if (data && data.length >= 752) {
|
|
1966
|
-
const maxAcctsV1M2 = readU64LE(data, V1M2_ENGINE_OFF + V1M2_ENGINE_PARAMS_OFF + 32);
|
|
1967
|
-
if (maxAcctsV1M2 === BigInt(vadln)) {
|
|
1968
|
-
return buildLayoutV1M2(vadln);
|
|
1969
|
-
}
|
|
1970
|
-
}
|
|
1971
|
-
return buildLayoutVADL(vadln);
|
|
1972
|
-
}
|
|
2291
|
+
if (vadln !== void 0) return buildLayoutVADL(vadln);
|
|
1973
2292
|
const v1mn = V1M_SIZES.get(dataLen);
|
|
1974
2293
|
if (v1mn !== void 0) return buildLayoutV1M(v1mn);
|
|
1975
2294
|
const v0n = V0_SIZES.get(dataLen);
|
|
@@ -2130,14 +2449,6 @@ function parseConfig(data, layoutHint) {
|
|
|
2130
2449
|
off += 8;
|
|
2131
2450
|
const fundingMaxBpsPerSlot = readI64LE(data, off);
|
|
2132
2451
|
off += 8;
|
|
2133
|
-
const fundingPremiumWeightBps = readU64LE(data, off);
|
|
2134
|
-
off += 8;
|
|
2135
|
-
const fundingSettlementIntervalSlots = readU64LE(data, off);
|
|
2136
|
-
off += 8;
|
|
2137
|
-
const fundingPremiumDampeningE6 = readU64LE(data, off);
|
|
2138
|
-
off += 8;
|
|
2139
|
-
const fundingPremiumMaxBpsPerSlot = readU64LE(data, off);
|
|
2140
|
-
off += 8;
|
|
2141
2452
|
const threshFloor = readU128LE(data, off);
|
|
2142
2453
|
off += 16;
|
|
2143
2454
|
const threshRiskBps = readU64LE(data, off);
|
|
@@ -2202,6 +2513,14 @@ function parseConfig(data, layoutHint) {
|
|
|
2202
2513
|
}
|
|
2203
2514
|
}
|
|
2204
2515
|
}
|
|
2516
|
+
let dexPool = null;
|
|
2517
|
+
const DEX_POOL_REL_OFF = 512;
|
|
2518
|
+
if (configLen >= DEX_POOL_REL_OFF + 32 && data.length >= configOff + DEX_POOL_REL_OFF + 32) {
|
|
2519
|
+
const dexPoolBytes = data.subarray(configOff + DEX_POOL_REL_OFF, configOff + DEX_POOL_REL_OFF + 32);
|
|
2520
|
+
if (dexPoolBytes.some((b) => b !== 0)) {
|
|
2521
|
+
dexPool = new PublicKey3(dexPoolBytes);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2205
2524
|
return {
|
|
2206
2525
|
collateralMint,
|
|
2207
2526
|
vaultPubkey,
|
|
@@ -2216,10 +2535,10 @@ function parseConfig(data, layoutHint) {
|
|
|
2216
2535
|
fundingInvScaleNotionalE6,
|
|
2217
2536
|
fundingMaxPremiumBps,
|
|
2218
2537
|
fundingMaxBpsPerSlot,
|
|
2219
|
-
fundingPremiumWeightBps,
|
|
2220
|
-
fundingSettlementIntervalSlots,
|
|
2221
|
-
fundingPremiumDampeningE6,
|
|
2222
|
-
fundingPremiumMaxBpsPerSlot,
|
|
2538
|
+
fundingPremiumWeightBps: 0n,
|
|
2539
|
+
fundingSettlementIntervalSlots: 0n,
|
|
2540
|
+
fundingPremiumDampeningE6: 0n,
|
|
2541
|
+
fundingPremiumMaxBpsPerSlot: 0n,
|
|
2223
2542
|
threshFloor,
|
|
2224
2543
|
threshRiskBps,
|
|
2225
2544
|
threshUpdateIntervalSlots,
|
|
@@ -2244,7 +2563,8 @@ function parseConfig(data, layoutHint) {
|
|
|
2244
2563
|
insuranceIsolationBps,
|
|
2245
2564
|
oraclePhase,
|
|
2246
2565
|
cumulativeVolumeE6,
|
|
2247
|
-
phase2DeltaSlots
|
|
2566
|
+
phase2DeltaSlots,
|
|
2567
|
+
dexPool
|
|
2248
2568
|
};
|
|
2249
2569
|
}
|
|
2250
2570
|
function parseParams(data, layoutHint) {
|
|
@@ -2384,16 +2704,17 @@ function parseAccount(data, idx) {
|
|
|
2384
2704
|
if (data.length < base + layout.accountSize) {
|
|
2385
2705
|
throw new Error("Slab data too short for account");
|
|
2386
2706
|
}
|
|
2387
|
-
const
|
|
2707
|
+
const isV12_1 = layout.engineOff === V12_1_ENGINE_OFF && (layout.accountSize === V12_1_ACCOUNT_SIZE || layout.accountSize === V12_1_ACCOUNT_SIZE_SBF);
|
|
2708
|
+
const isAdl = layout.accountSize >= 312 || isV12_1;
|
|
2388
2709
|
const warmupStartedOff = isAdl ? V_ADL_ACCT_WARMUP_STARTED_OFF : ACCT_WARMUP_STARTED_OFF;
|
|
2389
2710
|
const warmupSlopeOff = isAdl ? V_ADL_ACCT_WARMUP_SLOPE_OFF : ACCT_WARMUP_SLOPE_OFF;
|
|
2390
|
-
const positionSizeOff = isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
|
|
2391
|
-
const entryPriceOff = isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
|
|
2392
|
-
const fundingIndexOff = isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF;
|
|
2393
|
-
const matcherProgOff = isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
|
|
2394
|
-
const matcherCtxOff = isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
|
|
2395
|
-
const feeCreditsOff = isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
|
|
2396
|
-
const lastFeeSlotOff = isAdl ? V_ADL_ACCT_LAST_FEE_SLOT_OFF : ACCT_LAST_FEE_SLOT_OFF;
|
|
2711
|
+
const positionSizeOff = isV12_1 ? V12_1_ACCT_POSITION_SIZE_OFF : isAdl ? V_ADL_ACCT_POSITION_SIZE_OFF : ACCT_POSITION_SIZE_OFF;
|
|
2712
|
+
const entryPriceOff = isV12_1 ? V12_1_ACCT_ENTRY_PRICE_OFF : isAdl ? V_ADL_ACCT_ENTRY_PRICE_OFF : ACCT_ENTRY_PRICE_OFF;
|
|
2713
|
+
const fundingIndexOff = isV12_1 ? V12_1_ACCT_FUNDING_INDEX_OFF : isAdl ? V_ADL_ACCT_FUNDING_INDEX_OFF : ACCT_FUNDING_INDEX_OFF;
|
|
2714
|
+
const matcherProgOff = isV12_1 ? V12_1_ACCT_MATCHER_PROGRAM_OFF : isAdl ? V_ADL_ACCT_MATCHER_PROGRAM_OFF : ACCT_MATCHER_PROGRAM_OFF;
|
|
2715
|
+
const matcherCtxOff = isV12_1 ? V12_1_ACCT_MATCHER_CONTEXT_OFF : isAdl ? V_ADL_ACCT_MATCHER_CONTEXT_OFF : ACCT_MATCHER_CONTEXT_OFF;
|
|
2716
|
+
const feeCreditsOff = isV12_1 ? V12_1_ACCT_FEE_CREDITS_OFF : isAdl ? V_ADL_ACCT_FEE_CREDITS_OFF : ACCT_FEE_CREDITS_OFF;
|
|
2717
|
+
const lastFeeSlotOff = isV12_1 ? V12_1_ACCT_LAST_FEE_SLOT_OFF : isAdl ? V_ADL_ACCT_LAST_FEE_SLOT_OFF : ACCT_LAST_FEE_SLOT_OFF;
|
|
2397
2718
|
const kindByte = readU8(data, base + ACCT_KIND_OFF);
|
|
2398
2719
|
const kind = kindByte === 1 ? 1 /* LP */ : 0 /* User */;
|
|
2399
2720
|
return {
|
|
@@ -2405,8 +2726,10 @@ function parseAccount(data, idx) {
|
|
|
2405
2726
|
warmupStartedAtSlot: readU64LE(data, base + warmupStartedOff),
|
|
2406
2727
|
warmupSlopePerStep: readU128LE(data, base + warmupSlopeOff),
|
|
2407
2728
|
positionSize: readI128LE(data, base + positionSizeOff),
|
|
2408
|
-
entryPrice: readU64LE(data, base + entryPriceOff),
|
|
2409
|
-
|
|
2729
|
+
entryPrice: entryPriceOff >= 0 ? readU64LE(data, base + entryPriceOff) : 0n,
|
|
2730
|
+
// V12_1: entry_price removed
|
|
2731
|
+
// V12_1 changed funding_index from i128 to i64 (legacy field moved to end of account)
|
|
2732
|
+
fundingIndex: isV12_1 ? BigInt(readI64LE(data, base + fundingIndexOff)) : readI128LE(data, base + fundingIndexOff),
|
|
2410
2733
|
matcherProgram: new PublicKey3(data.subarray(base + matcherProgOff, base + matcherProgOff + 32)),
|
|
2411
2734
|
matcherContext: new PublicKey3(data.subarray(base + matcherCtxOff, base + matcherCtxOff + 32)),
|
|
2412
2735
|
owner: new PublicKey3(data.subarray(base + layout.acctOwnerOff, base + layout.acctOwnerOff + 32)),
|
|
@@ -2439,12 +2762,6 @@ function deriveVaultAuthority(programId, slab) {
|
|
|
2439
2762
|
programId
|
|
2440
2763
|
);
|
|
2441
2764
|
}
|
|
2442
|
-
function deriveInsuranceLpMint(programId, slab) {
|
|
2443
|
-
return PublicKey4.findProgramAddressSync(
|
|
2444
|
-
[textEncoder.encode("ins_lp"), slab.toBytes()],
|
|
2445
|
-
programId
|
|
2446
|
-
);
|
|
2447
|
-
}
|
|
2448
2765
|
var LP_INDEX_U16_MAX = 65535;
|
|
2449
2766
|
function deriveLpPda(programId, slab, lpIdx) {
|
|
2450
2767
|
if (typeof lpIdx !== "number" || !Number.isInteger(lpIdx) || lpIdx < 0 || lpIdx > LP_INDEX_U16_MAX) {
|
|
@@ -2501,7 +2818,14 @@ function derivePythPushOraclePDA(feedIdHex) {
|
|
|
2501
2818
|
}
|
|
2502
2819
|
const feedId = new Uint8Array(32);
|
|
2503
2820
|
for (let i = 0; i < 32; i++) {
|
|
2504
|
-
|
|
2821
|
+
const hexPair = normalized.substring(i * 2, i * 2 + 2);
|
|
2822
|
+
const byte = parseInt(hexPair, 16);
|
|
2823
|
+
if (Number.isNaN(byte)) {
|
|
2824
|
+
throw new Error(
|
|
2825
|
+
`derivePythPushOraclePDA: failed to parse hex byte at position ${i}: "${hexPair}"`
|
|
2826
|
+
);
|
|
2827
|
+
}
|
|
2828
|
+
feedId[i] = byte;
|
|
2505
2829
|
}
|
|
2506
2830
|
const shardBuf = new Uint8Array(2);
|
|
2507
2831
|
return PublicKey4.findProgramAddressSync(
|
|
@@ -2527,13 +2851,76 @@ async function fetchTokenAccount(connection, address, tokenProgramId = TOKEN_PRO
|
|
|
2527
2851
|
return getAccount(connection, address, void 0, tokenProgramId);
|
|
2528
2852
|
}
|
|
2529
2853
|
|
|
2854
|
+
// src/solana/discovery.ts
|
|
2855
|
+
import { PublicKey as PublicKey6 } from "@solana/web3.js";
|
|
2856
|
+
|
|
2857
|
+
// src/solana/static-markets.ts
|
|
2858
|
+
import { PublicKey as PublicKey5 } from "@solana/web3.js";
|
|
2859
|
+
var MAINNET_MARKETS = [
|
|
2860
|
+
// Populated at mainnet launch — currently empty.
|
|
2861
|
+
// To add entries:
|
|
2862
|
+
// { slabAddress: "ABC123...", symbol: "SOL-PERP", name: "SOL Perpetual" },
|
|
2863
|
+
];
|
|
2864
|
+
var DEVNET_MARKETS = [
|
|
2865
|
+
// Populated from prior discoverMarkets() runs on devnet.
|
|
2866
|
+
// These serve as the tier-3 safety net for devnet users.
|
|
2867
|
+
];
|
|
2868
|
+
var STATIC_REGISTRY = {
|
|
2869
|
+
mainnet: MAINNET_MARKETS,
|
|
2870
|
+
devnet: DEVNET_MARKETS
|
|
2871
|
+
};
|
|
2872
|
+
var USER_MARKETS = {
|
|
2873
|
+
mainnet: [],
|
|
2874
|
+
devnet: []
|
|
2875
|
+
};
|
|
2876
|
+
function getStaticMarkets(network) {
|
|
2877
|
+
const builtin = STATIC_REGISTRY[network] ?? [];
|
|
2878
|
+
const user = USER_MARKETS[network] ?? [];
|
|
2879
|
+
if (user.length === 0) return [...builtin];
|
|
2880
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2881
|
+
for (const entry of builtin) {
|
|
2882
|
+
seen.set(entry.slabAddress, entry);
|
|
2883
|
+
}
|
|
2884
|
+
for (const entry of user) {
|
|
2885
|
+
seen.set(entry.slabAddress, entry);
|
|
2886
|
+
}
|
|
2887
|
+
return [...seen.values()];
|
|
2888
|
+
}
|
|
2889
|
+
function registerStaticMarkets(network, entries) {
|
|
2890
|
+
const existing = USER_MARKETS[network];
|
|
2891
|
+
const seen = new Set(existing.map((e) => e.slabAddress));
|
|
2892
|
+
for (const entry of entries) {
|
|
2893
|
+
if (!entry.slabAddress) continue;
|
|
2894
|
+
if (seen.has(entry.slabAddress)) continue;
|
|
2895
|
+
try {
|
|
2896
|
+
new PublicKey5(entry.slabAddress);
|
|
2897
|
+
} catch {
|
|
2898
|
+
console.warn(
|
|
2899
|
+
`[registerStaticMarkets] Skipping invalid slabAddress: ${entry.slabAddress}`
|
|
2900
|
+
);
|
|
2901
|
+
continue;
|
|
2902
|
+
}
|
|
2903
|
+
seen.add(entry.slabAddress);
|
|
2904
|
+
existing.push(entry);
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
function clearStaticMarkets(network) {
|
|
2908
|
+
if (network) {
|
|
2909
|
+
USER_MARKETS[network] = [];
|
|
2910
|
+
} else {
|
|
2911
|
+
USER_MARKETS.mainnet = [];
|
|
2912
|
+
USER_MARKETS.devnet = [];
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2530
2916
|
// src/solana/discovery.ts
|
|
2531
2917
|
var ENGINE_BITMAP_OFF_V0 = 320;
|
|
2532
2918
|
var MAGIC_BYTES = new Uint8Array([84, 65, 76, 79, 67, 82, 69, 80]);
|
|
2533
2919
|
var SLAB_TIERS = {
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2920
|
+
micro: SLAB_TIERS_V12_1["micro"],
|
|
2921
|
+
small: SLAB_TIERS_V12_1["small"],
|
|
2922
|
+
medium: SLAB_TIERS_V12_1["medium"],
|
|
2923
|
+
large: SLAB_TIERS_V12_1["large"]
|
|
2537
2924
|
};
|
|
2538
2925
|
var SLAB_TIERS_V0 = {
|
|
2539
2926
|
small: { maxAccounts: 256, dataSize: 62808, label: "Small", description: "256 slots \xB7 ~0.44 SOL" },
|
|
@@ -2911,22 +3298,77 @@ async function discoverMarkets(connection, programId, options = {}) {
|
|
|
2911
3298
|
"[discoverMarkets] dataSize filters failed, falling back to memcmp:",
|
|
2912
3299
|
err instanceof Error ? err.message : err
|
|
2913
3300
|
);
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
3301
|
+
try {
|
|
3302
|
+
const fallback = await connection.getProgramAccounts(programId, {
|
|
3303
|
+
filters: [
|
|
3304
|
+
{
|
|
3305
|
+
memcmp: {
|
|
3306
|
+
offset: 0,
|
|
3307
|
+
bytes: "F6P2QNqpQV5"
|
|
3308
|
+
// base58 of TALOCREP (u64 LE magic)
|
|
3309
|
+
}
|
|
2921
3310
|
}
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
3311
|
+
],
|
|
3312
|
+
dataSlice: { offset: 0, length: HEADER_SLICE_LENGTH }
|
|
3313
|
+
});
|
|
3314
|
+
rawAccounts = [...fallback].map((e) => ({ ...e, maxAccounts: 4096, dataSize: SLAB_TIERS.large.dataSize }));
|
|
3315
|
+
} catch (memcmpErr) {
|
|
3316
|
+
console.warn(
|
|
3317
|
+
"[discoverMarkets] memcmp fallback also failed:",
|
|
3318
|
+
memcmpErr instanceof Error ? memcmpErr.message : memcmpErr
|
|
3319
|
+
);
|
|
3320
|
+
}
|
|
2927
3321
|
}
|
|
2928
|
-
|
|
2929
|
-
|
|
3322
|
+
if (rawAccounts.length === 0 && options.apiBaseUrl) {
|
|
3323
|
+
console.warn(
|
|
3324
|
+
"[discoverMarkets] RPC discovery returned 0 markets, falling back to REST API"
|
|
3325
|
+
);
|
|
3326
|
+
try {
|
|
3327
|
+
const apiResult = await discoverMarketsViaApi(
|
|
3328
|
+
connection,
|
|
3329
|
+
programId,
|
|
3330
|
+
options.apiBaseUrl,
|
|
3331
|
+
{ timeoutMs: options.apiTimeoutMs }
|
|
3332
|
+
);
|
|
3333
|
+
if (apiResult.length > 0) {
|
|
3334
|
+
return apiResult;
|
|
3335
|
+
}
|
|
3336
|
+
console.warn(
|
|
3337
|
+
"[discoverMarkets] REST API returned 0 markets, checking tier-3 static bundle"
|
|
3338
|
+
);
|
|
3339
|
+
} catch (apiErr) {
|
|
3340
|
+
console.warn(
|
|
3341
|
+
"[discoverMarkets] API fallback also failed:",
|
|
3342
|
+
apiErr instanceof Error ? apiErr.message : apiErr
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
if (rawAccounts.length === 0 && options.network) {
|
|
3347
|
+
const staticEntries = getStaticMarkets(options.network);
|
|
3348
|
+
if (staticEntries.length > 0) {
|
|
3349
|
+
console.warn(
|
|
3350
|
+
`[discoverMarkets] Tier 1+2 failed, falling back to static bundle (${staticEntries.length} addresses for ${options.network})`
|
|
3351
|
+
);
|
|
3352
|
+
try {
|
|
3353
|
+
return await discoverMarketsViaStaticBundle(
|
|
3354
|
+
connection,
|
|
3355
|
+
programId,
|
|
3356
|
+
staticEntries
|
|
3357
|
+
);
|
|
3358
|
+
} catch (staticErr) {
|
|
3359
|
+
console.warn(
|
|
3360
|
+
"[discoverMarkets] Static bundle fallback also failed:",
|
|
3361
|
+
staticErr instanceof Error ? staticErr.message : staticErr
|
|
3362
|
+
);
|
|
3363
|
+
}
|
|
3364
|
+
} else {
|
|
3365
|
+
console.warn(
|
|
3366
|
+
`[discoverMarkets] Static bundle has 0 entries for ${options.network} \u2014 skipping tier 3`
|
|
3367
|
+
);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
const accounts = rawAccounts;
|
|
3371
|
+
const markets = [];
|
|
2930
3372
|
const seenPubkeys = /* @__PURE__ */ new Set();
|
|
2931
3373
|
for (const { pubkey, account, maxAccounts, dataSize } of accounts) {
|
|
2932
3374
|
const pkStr = pubkey.toBase58();
|
|
@@ -2963,9 +3405,145 @@ async function discoverMarkets(connection, programId, options = {}) {
|
|
|
2963
3405
|
}
|
|
2964
3406
|
return markets;
|
|
2965
3407
|
}
|
|
3408
|
+
async function getMarketsByAddress(connection, programId, addresses, options = {}) {
|
|
3409
|
+
if (addresses.length === 0) return [];
|
|
3410
|
+
const {
|
|
3411
|
+
batchSize = 100,
|
|
3412
|
+
interBatchDelayMs = 0
|
|
3413
|
+
} = options;
|
|
3414
|
+
const effectiveBatchSize = Math.max(1, Math.min(batchSize, 100));
|
|
3415
|
+
const fetched = [];
|
|
3416
|
+
for (let offset = 0; offset < addresses.length; offset += effectiveBatchSize) {
|
|
3417
|
+
const batch = addresses.slice(offset, offset + effectiveBatchSize);
|
|
3418
|
+
const response = await connection.getMultipleAccountsInfo(batch);
|
|
3419
|
+
for (let i = 0; i < batch.length; i++) {
|
|
3420
|
+
const info = response[i];
|
|
3421
|
+
if (info && info.data) {
|
|
3422
|
+
if (!info.owner.equals(programId)) {
|
|
3423
|
+
console.warn(
|
|
3424
|
+
`[getMarketsByAddress] Skipping ${batch[i].toBase58()}: owner mismatch (expected ${programId.toBase58()}, got ${info.owner.toBase58()})`
|
|
3425
|
+
);
|
|
3426
|
+
continue;
|
|
3427
|
+
}
|
|
3428
|
+
fetched.push({ pubkey: batch[i], data: info.data });
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
if (interBatchDelayMs > 0 && offset + effectiveBatchSize < addresses.length) {
|
|
3432
|
+
await new Promise((r) => setTimeout(r, interBatchDelayMs));
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
const markets = [];
|
|
3436
|
+
for (const entry of fetched) {
|
|
3437
|
+
if (!entry) continue;
|
|
3438
|
+
const { pubkey, data: rawData } = entry;
|
|
3439
|
+
const data = new Uint8Array(rawData);
|
|
3440
|
+
let valid = true;
|
|
3441
|
+
for (let i = 0; i < MAGIC_BYTES.length; i++) {
|
|
3442
|
+
if (data[i] !== MAGIC_BYTES[i]) {
|
|
3443
|
+
valid = false;
|
|
3444
|
+
break;
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
if (!valid) {
|
|
3448
|
+
console.warn(
|
|
3449
|
+
`[getMarketsByAddress] Skipping ${pubkey.toBase58()}: invalid magic bytes`
|
|
3450
|
+
);
|
|
3451
|
+
continue;
|
|
3452
|
+
}
|
|
3453
|
+
const layout = detectSlabLayout(data.length, data);
|
|
3454
|
+
if (!layout) {
|
|
3455
|
+
console.warn(
|
|
3456
|
+
`[getMarketsByAddress] Skipping ${pubkey.toBase58()}: unrecognized layout for dataSize=${data.length}`
|
|
3457
|
+
);
|
|
3458
|
+
continue;
|
|
3459
|
+
}
|
|
3460
|
+
try {
|
|
3461
|
+
const header = parseHeader(data);
|
|
3462
|
+
const config = parseConfig(data, layout);
|
|
3463
|
+
const engine = parseEngineLight(data, layout, layout.maxAccounts);
|
|
3464
|
+
const params = parseParams(data, layout);
|
|
3465
|
+
markets.push({ slabAddress: pubkey, programId, header, config, engine, params });
|
|
3466
|
+
} catch (err) {
|
|
3467
|
+
console.warn(
|
|
3468
|
+
`[getMarketsByAddress] Failed to parse account ${pubkey.toBase58()}:`,
|
|
3469
|
+
err instanceof Error ? err.message : err
|
|
3470
|
+
);
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
return markets;
|
|
3474
|
+
}
|
|
3475
|
+
async function discoverMarketsViaApi(connection, programId, apiBaseUrl, options = {}) {
|
|
3476
|
+
const { timeoutMs = 1e4, onChainOptions } = options;
|
|
3477
|
+
const base = apiBaseUrl.replace(/\/+$/, "");
|
|
3478
|
+
const url = `${base}/markets`;
|
|
3479
|
+
const controller = new AbortController();
|
|
3480
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3481
|
+
let response;
|
|
3482
|
+
try {
|
|
3483
|
+
response = await fetch(url, {
|
|
3484
|
+
method: "GET",
|
|
3485
|
+
headers: { Accept: "application/json" },
|
|
3486
|
+
signal: controller.signal
|
|
3487
|
+
});
|
|
3488
|
+
} finally {
|
|
3489
|
+
clearTimeout(timer);
|
|
3490
|
+
}
|
|
3491
|
+
if (!response.ok) {
|
|
3492
|
+
throw new Error(
|
|
3493
|
+
`[discoverMarketsViaApi] API returned ${response.status} ${response.statusText} from ${url}`
|
|
3494
|
+
);
|
|
3495
|
+
}
|
|
3496
|
+
const body = await response.json();
|
|
3497
|
+
const apiMarkets = body.markets;
|
|
3498
|
+
if (!Array.isArray(apiMarkets) || apiMarkets.length === 0) {
|
|
3499
|
+
console.warn("[discoverMarketsViaApi] API returned 0 markets");
|
|
3500
|
+
return [];
|
|
3501
|
+
}
|
|
3502
|
+
const addresses = [];
|
|
3503
|
+
for (const entry of apiMarkets) {
|
|
3504
|
+
if (!entry.slab_address || typeof entry.slab_address !== "string") continue;
|
|
3505
|
+
try {
|
|
3506
|
+
addresses.push(new PublicKey6(entry.slab_address));
|
|
3507
|
+
} catch {
|
|
3508
|
+
console.warn(
|
|
3509
|
+
`[discoverMarketsViaApi] Skipping invalid slab address: ${entry.slab_address}`
|
|
3510
|
+
);
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
if (addresses.length === 0) {
|
|
3514
|
+
console.warn("[discoverMarketsViaApi] No valid slab addresses from API");
|
|
3515
|
+
return [];
|
|
3516
|
+
}
|
|
3517
|
+
console.log(
|
|
3518
|
+
`[discoverMarketsViaApi] API returned ${addresses.length} slab addresses, fetching on-chain data`
|
|
3519
|
+
);
|
|
3520
|
+
return getMarketsByAddress(connection, programId, addresses, onChainOptions);
|
|
3521
|
+
}
|
|
3522
|
+
async function discoverMarketsViaStaticBundle(connection, programId, entries, options = {}) {
|
|
3523
|
+
if (entries.length === 0) return [];
|
|
3524
|
+
const addresses = [];
|
|
3525
|
+
for (const entry of entries) {
|
|
3526
|
+
if (!entry.slabAddress || typeof entry.slabAddress !== "string") continue;
|
|
3527
|
+
try {
|
|
3528
|
+
addresses.push(new PublicKey6(entry.slabAddress));
|
|
3529
|
+
} catch {
|
|
3530
|
+
console.warn(
|
|
3531
|
+
`[discoverMarketsViaStaticBundle] Skipping invalid slab address: ${entry.slabAddress}`
|
|
3532
|
+
);
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
if (addresses.length === 0) {
|
|
3536
|
+
console.warn("[discoverMarketsViaStaticBundle] No valid slab addresses in static bundle");
|
|
3537
|
+
return [];
|
|
3538
|
+
}
|
|
3539
|
+
console.log(
|
|
3540
|
+
`[discoverMarketsViaStaticBundle] Fetching ${addresses.length} slab addresses on-chain`
|
|
3541
|
+
);
|
|
3542
|
+
return getMarketsByAddress(connection, programId, addresses, options.onChainOptions);
|
|
3543
|
+
}
|
|
2966
3544
|
|
|
2967
3545
|
// src/solana/dex-oracle.ts
|
|
2968
|
-
import { PublicKey as
|
|
3546
|
+
import { PublicKey as PublicKey7 } from "@solana/web3.js";
|
|
2969
3547
|
function detectDexType(ownerProgramId) {
|
|
2970
3548
|
if (ownerProgramId.equals(PUMPSWAP_PROGRAM_ID)) return "pumpswap";
|
|
2971
3549
|
if (ownerProgramId.equals(RAYDIUM_CLMM_PROGRAM_ID)) return "raydium-clmm";
|
|
@@ -3001,10 +3579,10 @@ function parsePumpSwapPool(poolAddress, data) {
|
|
|
3001
3579
|
return {
|
|
3002
3580
|
dexType: "pumpswap",
|
|
3003
3581
|
poolAddress,
|
|
3004
|
-
baseMint: new
|
|
3005
|
-
quoteMint: new
|
|
3006
|
-
baseVault: new
|
|
3007
|
-
quoteVault: new
|
|
3582
|
+
baseMint: new PublicKey7(data.slice(35, 67)),
|
|
3583
|
+
quoteMint: new PublicKey7(data.slice(67, 99)),
|
|
3584
|
+
baseVault: new PublicKey7(data.slice(131, 163)),
|
|
3585
|
+
quoteVault: new PublicKey7(data.slice(163, 195))
|
|
3008
3586
|
};
|
|
3009
3587
|
}
|
|
3010
3588
|
var SPL_TOKEN_AMOUNT_MIN_LEN = 72;
|
|
@@ -3030,8 +3608,8 @@ function parseRaydiumClmmPool(poolAddress, data) {
|
|
|
3030
3608
|
return {
|
|
3031
3609
|
dexType: "raydium-clmm",
|
|
3032
3610
|
poolAddress,
|
|
3033
|
-
baseMint: new
|
|
3034
|
-
quoteMint: new
|
|
3611
|
+
baseMint: new PublicKey7(data.slice(73, 105)),
|
|
3612
|
+
quoteMint: new PublicKey7(data.slice(105, 137))
|
|
3035
3613
|
};
|
|
3036
3614
|
}
|
|
3037
3615
|
var MAX_TOKEN_DECIMALS = 24;
|
|
@@ -3049,9 +3627,7 @@ function computeRaydiumClmmPriceE6(data) {
|
|
|
3049
3627
|
}
|
|
3050
3628
|
const sqrtPriceX64 = readU128LE3(dv3, 253);
|
|
3051
3629
|
if (sqrtPriceX64 === 0n) return 0n;
|
|
3052
|
-
const
|
|
3053
|
-
const term = scaledSqrt >> 64n;
|
|
3054
|
-
const priceE6Raw = term * sqrtPriceX64 >> 64n;
|
|
3630
|
+
const priceE6Raw = sqrtPriceX64 * sqrtPriceX64 * 1000000n >> 128n;
|
|
3055
3631
|
const decimalDiff = 6 + decimals0 - decimals1;
|
|
3056
3632
|
const adjustedDiff = decimalDiff - 6;
|
|
3057
3633
|
if (adjustedDiff >= 0) {
|
|
@@ -3070,8 +3646,8 @@ function parseMeteoraPool(poolAddress, data) {
|
|
|
3070
3646
|
return {
|
|
3071
3647
|
dexType: "meteora-dlmm",
|
|
3072
3648
|
poolAddress,
|
|
3073
|
-
baseMint: new
|
|
3074
|
-
quoteMint: new
|
|
3649
|
+
baseMint: new PublicKey7(data.slice(81, 113)),
|
|
3650
|
+
quoteMint: new PublicKey7(data.slice(113, 145))
|
|
3075
3651
|
};
|
|
3076
3652
|
}
|
|
3077
3653
|
var MAX_BIN_STEP = 1e4;
|
|
@@ -3104,7 +3680,14 @@ function computeMeteoraDlmmPriceE6(data) {
|
|
|
3104
3680
|
let exp = isNeg ? BigInt(-activeId) : BigInt(activeId);
|
|
3105
3681
|
let result = SCALE;
|
|
3106
3682
|
let b = base;
|
|
3683
|
+
let iterations = 0;
|
|
3684
|
+
const MAX_ITERATIONS = 25;
|
|
3107
3685
|
while (exp > 0n) {
|
|
3686
|
+
if (iterations++ >= MAX_ITERATIONS) {
|
|
3687
|
+
throw new Error(
|
|
3688
|
+
`Meteora DLMM: exponentiation loop exceeded ${MAX_ITERATIONS} iterations (activeId=${activeId})`
|
|
3689
|
+
);
|
|
3690
|
+
}
|
|
3108
3691
|
if (exp & 1n) {
|
|
3109
3692
|
result = result * b / SCALE;
|
|
3110
3693
|
}
|
|
@@ -3135,6 +3718,7 @@ function readU128LE3(dv3, offset) {
|
|
|
3135
3718
|
var CHAINLINK_MIN_SIZE = 224;
|
|
3136
3719
|
var MAX_DECIMALS = 18;
|
|
3137
3720
|
var CHAINLINK_DECIMALS_OFFSET = 138;
|
|
3721
|
+
var CHAINLINK_TIMESTAMP_OFFSET = 168;
|
|
3138
3722
|
var CHAINLINK_ANSWER_OFFSET = 216;
|
|
3139
3723
|
function readU82(data, off) {
|
|
3140
3724
|
return data[off];
|
|
@@ -3142,7 +3726,7 @@ function readU82(data, off) {
|
|
|
3142
3726
|
function readBigInt64LE(data, off) {
|
|
3143
3727
|
return new DataView(data.buffer, data.byteOffset, data.byteLength).getBigInt64(off, true);
|
|
3144
3728
|
}
|
|
3145
|
-
function parseChainlinkPrice(data) {
|
|
3729
|
+
function parseChainlinkPrice(data, options) {
|
|
3146
3730
|
if (data.length < CHAINLINK_MIN_SIZE) {
|
|
3147
3731
|
throw new Error(
|
|
3148
3732
|
`Oracle account data too small: ${data.length} bytes (need at least ${CHAINLINK_MIN_SIZE})`
|
|
@@ -3160,7 +3744,18 @@ function parseChainlinkPrice(data) {
|
|
|
3160
3744
|
`Oracle price is non-positive: ${price}`
|
|
3161
3745
|
);
|
|
3162
3746
|
}
|
|
3163
|
-
|
|
3747
|
+
const updatedAtBig = readBigInt64LE(data, CHAINLINK_TIMESTAMP_OFFSET);
|
|
3748
|
+
const updatedAt = Number(updatedAtBig);
|
|
3749
|
+
if (options?.maxStalenessSeconds !== void 0 && updatedAt > 0) {
|
|
3750
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
3751
|
+
const age = now - updatedAt;
|
|
3752
|
+
if (age > options.maxStalenessSeconds) {
|
|
3753
|
+
throw new Error(
|
|
3754
|
+
`Oracle price is stale: last updated ${age}s ago (max ${options.maxStalenessSeconds}s)`
|
|
3755
|
+
);
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
return { price, decimals, updatedAt: updatedAt > 0 ? updatedAt : void 0 };
|
|
3164
3759
|
}
|
|
3165
3760
|
function isValidChainlinkOracle(data) {
|
|
3166
3761
|
try {
|
|
@@ -3172,15 +3767,19 @@ function isValidChainlinkOracle(data) {
|
|
|
3172
3767
|
}
|
|
3173
3768
|
|
|
3174
3769
|
// src/solana/token-program.ts
|
|
3175
|
-
import { PublicKey as
|
|
3770
|
+
import { PublicKey as PublicKey8 } from "@solana/web3.js";
|
|
3176
3771
|
import { TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID3 } from "@solana/spl-token";
|
|
3177
|
-
var TOKEN_2022_PROGRAM_ID = new
|
|
3772
|
+
var TOKEN_2022_PROGRAM_ID = new PublicKey8(
|
|
3178
3773
|
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
|
|
3179
3774
|
);
|
|
3180
3775
|
async function detectTokenProgram(connection, mint) {
|
|
3181
3776
|
const info = await connection.getAccountInfo(mint);
|
|
3182
3777
|
if (!info) throw new Error(`Mint account not found: ${mint.toBase58()}`);
|
|
3183
|
-
|
|
3778
|
+
if (info.owner.equals(TOKEN_PROGRAM_ID3)) return TOKEN_PROGRAM_ID3;
|
|
3779
|
+
if (info.owner.equals(TOKEN_2022_PROGRAM_ID)) return TOKEN_2022_PROGRAM_ID;
|
|
3780
|
+
throw new Error(
|
|
3781
|
+
`Mint ${mint.toBase58()} is owned by ${info.owner.toBase58()}, which is neither TOKEN_PROGRAM_ID nor TOKEN_2022_PROGRAM_ID`
|
|
3782
|
+
);
|
|
3184
3783
|
}
|
|
3185
3784
|
function isToken2022(tokenProgramId) {
|
|
3186
3785
|
return tokenProgramId.equals(TOKEN_2022_PROGRAM_ID);
|
|
@@ -3190,11 +3789,11 @@ function isStandardToken(tokenProgramId) {
|
|
|
3190
3789
|
}
|
|
3191
3790
|
|
|
3192
3791
|
// src/solana/stake.ts
|
|
3193
|
-
import { PublicKey as
|
|
3792
|
+
import { PublicKey as PublicKey10, SystemProgram as SystemProgram2, SYSVAR_RENT_PUBKEY as SYSVAR_RENT_PUBKEY2, SYSVAR_CLOCK_PUBKEY as SYSVAR_CLOCK_PUBKEY2 } from "@solana/web3.js";
|
|
3194
3793
|
import { TOKEN_PROGRAM_ID as TOKEN_PROGRAM_ID4 } from "@solana/spl-token";
|
|
3195
3794
|
|
|
3196
3795
|
// src/config/program-ids.ts
|
|
3197
|
-
import { PublicKey as
|
|
3796
|
+
import { PublicKey as PublicKey9 } from "@solana/web3.js";
|
|
3198
3797
|
function safeEnv(key) {
|
|
3199
3798
|
try {
|
|
3200
3799
|
return typeof process !== "undefined" && process?.env ? process.env[key] : void 0;
|
|
@@ -3208,30 +3807,34 @@ var PROGRAM_IDS = {
|
|
|
3208
3807
|
matcher: "GTRgyTDfrMvBubALAqtHuQwT8tbGyXid7svXZKtWfC9k"
|
|
3209
3808
|
},
|
|
3210
3809
|
mainnet: {
|
|
3211
|
-
percolator: "
|
|
3810
|
+
percolator: "ESa89R5Es3rJ5mnwGybVRG1GrNt9etP11Z5V2QWD4edv",
|
|
3212
3811
|
matcher: "DHP6DtwXP1yJsz8YzfoeigRFPB979gzmumkmCxDLSkUX"
|
|
3213
3812
|
}
|
|
3214
3813
|
};
|
|
3215
3814
|
function getProgramId(network) {
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3815
|
+
if (!network) {
|
|
3816
|
+
const override = safeEnv("PROGRAM_ID");
|
|
3817
|
+
if (override) {
|
|
3818
|
+
console.warn(
|
|
3819
|
+
`[percolator-sdk] PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
3820
|
+
);
|
|
3821
|
+
return new PublicKey9(override);
|
|
3822
|
+
}
|
|
3222
3823
|
}
|
|
3223
3824
|
const detectedNetwork = getCurrentNetwork();
|
|
3224
3825
|
const targetNetwork = network ?? detectedNetwork;
|
|
3225
3826
|
const programId = PROGRAM_IDS[targetNetwork].percolator;
|
|
3226
|
-
return new
|
|
3827
|
+
return new PublicKey9(programId);
|
|
3227
3828
|
}
|
|
3228
3829
|
function getMatcherProgramId(network) {
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3830
|
+
if (!network) {
|
|
3831
|
+
const override = safeEnv("MATCHER_PROGRAM_ID");
|
|
3832
|
+
if (override) {
|
|
3833
|
+
console.warn(
|
|
3834
|
+
`[percolator-sdk] MATCHER_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
3835
|
+
);
|
|
3836
|
+
return new PublicKey9(override);
|
|
3837
|
+
}
|
|
3235
3838
|
}
|
|
3236
3839
|
const detectedNetwork = getCurrentNetwork();
|
|
3237
3840
|
const targetNetwork = network ?? detectedNetwork;
|
|
@@ -3239,7 +3842,7 @@ function getMatcherProgramId(network) {
|
|
|
3239
3842
|
if (!programId) {
|
|
3240
3843
|
throw new Error(`Matcher program not deployed on ${targetNetwork}`);
|
|
3241
3844
|
}
|
|
3242
|
-
return new
|
|
3845
|
+
return new PublicKey9(programId);
|
|
3243
3846
|
}
|
|
3244
3847
|
function getCurrentNetwork() {
|
|
3245
3848
|
const network = safeEnv("NETWORK")?.toLowerCase();
|
|
@@ -3252,8 +3855,7 @@ function getCurrentNetwork() {
|
|
|
3252
3855
|
// src/solana/stake.ts
|
|
3253
3856
|
var STAKE_PROGRAM_IDS = {
|
|
3254
3857
|
devnet: "6aJb1F9CDCVWCNYFwj8aQsVb696YnW6J1FznteHq4Q6k",
|
|
3255
|
-
mainnet: ""
|
|
3256
|
-
// TODO: populate once DevOps deploys percolator-stake to mainnet
|
|
3858
|
+
mainnet: "DC5fovFQD5SZYsetwvEqd4Wi4PFY1Yfnc669VMe6oa7F"
|
|
3257
3859
|
};
|
|
3258
3860
|
function getStakeProgramId(network) {
|
|
3259
3861
|
const override = safeEnv("STAKE_PROGRAM_ID");
|
|
@@ -3261,7 +3863,7 @@ function getStakeProgramId(network) {
|
|
|
3261
3863
|
console.warn(
|
|
3262
3864
|
`[percolator-sdk] STAKE_PROGRAM_ID env override active: ${override} \u2014 ensure this points to a trusted program`
|
|
3263
3865
|
);
|
|
3264
|
-
return new
|
|
3866
|
+
return new PublicKey10(override);
|
|
3265
3867
|
}
|
|
3266
3868
|
const detectedNetwork = network ?? (() => {
|
|
3267
3869
|
const n = safeEnv("NEXT_PUBLIC_DEFAULT_NETWORK")?.toLowerCase() ?? safeEnv("NETWORK")?.toLowerCase() ?? "";
|
|
@@ -3273,9 +3875,9 @@ function getStakeProgramId(network) {
|
|
|
3273
3875
|
`Stake program not deployed on ${detectedNetwork}. Set STAKE_PROGRAM_ID env var or wait for DevOps to deploy and update STAKE_PROGRAM_IDS.mainnet.`
|
|
3274
3876
|
);
|
|
3275
3877
|
}
|
|
3276
|
-
return new
|
|
3878
|
+
return new PublicKey10(id);
|
|
3277
3879
|
}
|
|
3278
|
-
var STAKE_PROGRAM_ID = new
|
|
3880
|
+
var STAKE_PROGRAM_ID = new PublicKey10(STAKE_PROGRAM_IDS.mainnet);
|
|
3279
3881
|
var STAKE_IX = {
|
|
3280
3882
|
InitPool: 0,
|
|
3281
3883
|
Deposit: 1,
|
|
@@ -3302,19 +3904,19 @@ var STAKE_IX = {
|
|
|
3302
3904
|
};
|
|
3303
3905
|
var TEXT = new TextEncoder();
|
|
3304
3906
|
function deriveStakePool(slab, programId) {
|
|
3305
|
-
return
|
|
3907
|
+
return PublicKey10.findProgramAddressSync(
|
|
3306
3908
|
[TEXT.encode("stake_pool"), slab.toBytes()],
|
|
3307
3909
|
programId ?? getStakeProgramId()
|
|
3308
3910
|
);
|
|
3309
3911
|
}
|
|
3310
3912
|
function deriveStakeVaultAuth(pool, programId) {
|
|
3311
|
-
return
|
|
3913
|
+
return PublicKey10.findProgramAddressSync(
|
|
3312
3914
|
[TEXT.encode("vault_auth"), pool.toBytes()],
|
|
3313
3915
|
programId ?? getStakeProgramId()
|
|
3314
3916
|
);
|
|
3315
3917
|
}
|
|
3316
3918
|
function deriveDepositPda(pool, user, programId) {
|
|
3317
|
-
return
|
|
3919
|
+
return PublicKey10.findProgramAddressSync(
|
|
3318
3920
|
[TEXT.encode("deposit"), pool.toBytes(), user.toBytes()],
|
|
3319
3921
|
programId ?? getStakeProgramId()
|
|
3320
3922
|
);
|
|
@@ -3336,6 +3938,9 @@ function readU16LE3(data, off) {
|
|
|
3336
3938
|
);
|
|
3337
3939
|
}
|
|
3338
3940
|
function u64Le(v) {
|
|
3941
|
+
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
3942
|
+
throw new Error(`u64Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
|
|
3943
|
+
}
|
|
3339
3944
|
const big = BigInt(v);
|
|
3340
3945
|
if (big < 0n) throw new Error(`u64Le: value must be non-negative, got ${big}`);
|
|
3341
3946
|
if (big > 0xFFFFFFFFFFFFFFFFn) throw new Error(`u64Le: value exceeds u64 max`);
|
|
@@ -3344,6 +3949,9 @@ function u64Le(v) {
|
|
|
3344
3949
|
return arr;
|
|
3345
3950
|
}
|
|
3346
3951
|
function u128Le(v) {
|
|
3952
|
+
if (typeof v === "number" && !Number.isSafeInteger(v)) {
|
|
3953
|
+
throw new Error(`u128Le: number ${v} exceeds Number.MAX_SAFE_INTEGER \u2014 use BigInt`);
|
|
3954
|
+
}
|
|
3347
3955
|
const big = BigInt(v);
|
|
3348
3956
|
if (big < 0n) throw new Error(`u128Le: value must be non-negative, got ${big}`);
|
|
3349
3957
|
if (big > (1n << 128n) - 1n) throw new Error(`u128Le: value exceeds u128 max`);
|
|
@@ -3354,7 +3962,7 @@ function u128Le(v) {
|
|
|
3354
3962
|
return arr;
|
|
3355
3963
|
}
|
|
3356
3964
|
function u16Le(v) {
|
|
3357
|
-
if (v < 0 || v > 65535) throw new Error(`u16Le: value
|
|
3965
|
+
if (!Number.isInteger(v) || v < 0 || v > 65535) throw new Error(`u16Le: value must be integer in range 0..65535, got ${v}`);
|
|
3358
3966
|
const arr = new Uint8Array(2);
|
|
3359
3967
|
new DataView(arr.buffer).setUint16(0, v, true);
|
|
3360
3968
|
return arr;
|
|
@@ -3465,15 +4073,15 @@ function decodeStakePool(data) {
|
|
|
3465
4073
|
const adminTransferred = bytes[off] === 1;
|
|
3466
4074
|
off += 1;
|
|
3467
4075
|
off += 4;
|
|
3468
|
-
const slab = new
|
|
4076
|
+
const slab = new PublicKey10(bytes.subarray(off, off + 32));
|
|
3469
4077
|
off += 32;
|
|
3470
|
-
const admin = new
|
|
4078
|
+
const admin = new PublicKey10(bytes.subarray(off, off + 32));
|
|
3471
4079
|
off += 32;
|
|
3472
|
-
const collateralMint = new
|
|
4080
|
+
const collateralMint = new PublicKey10(bytes.subarray(off, off + 32));
|
|
3473
4081
|
off += 32;
|
|
3474
|
-
const lpMint = new
|
|
4082
|
+
const lpMint = new PublicKey10(bytes.subarray(off, off + 32));
|
|
3475
4083
|
off += 32;
|
|
3476
|
-
const vault = new
|
|
4084
|
+
const vault = new PublicKey10(bytes.subarray(off, off + 32));
|
|
3477
4085
|
off += 32;
|
|
3478
4086
|
const totalDeposited = readU64LE4(bytes, off);
|
|
3479
4087
|
off += 8;
|
|
@@ -3489,7 +4097,7 @@ function decodeStakePool(data) {
|
|
|
3489
4097
|
off += 8;
|
|
3490
4098
|
const totalWithdrawn = readU64LE4(bytes, off);
|
|
3491
4099
|
off += 8;
|
|
3492
|
-
const percolatorProgram = new
|
|
4100
|
+
const percolatorProgram = new PublicKey10(bytes.subarray(off, off + 32));
|
|
3493
4101
|
off += 32;
|
|
3494
4102
|
const totalFeesEarned = readU64LE4(bytes, off);
|
|
3495
4103
|
off += 8;
|
|
@@ -3609,7 +4217,9 @@ function computePnlPct(pnl, capital) {
|
|
|
3609
4217
|
}
|
|
3610
4218
|
function isAdlTriggered(slabData) {
|
|
3611
4219
|
const layout = detectSlabLayout(slabData.length);
|
|
3612
|
-
if (!layout)
|
|
4220
|
+
if (!layout) {
|
|
4221
|
+
return false;
|
|
4222
|
+
}
|
|
3613
4223
|
try {
|
|
3614
4224
|
const engine = parseEngine(slabData);
|
|
3615
4225
|
if (engine.pnlPosTot === 0n) return false;
|
|
@@ -3652,6 +4262,14 @@ function rankAdlPositions(slabData) {
|
|
|
3652
4262
|
if (account.kind !== 0 /* User */) continue;
|
|
3653
4263
|
if (account.positionSize === 0n) continue;
|
|
3654
4264
|
const side = account.positionSize > 0n ? "long" : "short";
|
|
4265
|
+
if (side === "long" && account.positionSize <= 0n) {
|
|
4266
|
+
console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=long but positionSize=${account.positionSize}`);
|
|
4267
|
+
continue;
|
|
4268
|
+
}
|
|
4269
|
+
if (side === "short" && account.positionSize >= 0n) {
|
|
4270
|
+
console.warn(`[fetchAdlRankedPositions] account idx=${idx}: side=short but positionSize=${account.positionSize}`);
|
|
4271
|
+
continue;
|
|
4272
|
+
}
|
|
3655
4273
|
const pnlPct = computePnlPct(account.pnl, account.capital);
|
|
3656
4274
|
positions.push({
|
|
3657
4275
|
idx,
|
|
@@ -3725,7 +4343,11 @@ function parseAdlEvent(logs) {
|
|
|
3725
4343
|
}
|
|
3726
4344
|
if (tag !== ADL_EVENT_TAG) continue;
|
|
3727
4345
|
try {
|
|
3728
|
-
const
|
|
4346
|
+
const targetIdxBig = BigInt(match[2]);
|
|
4347
|
+
if (targetIdxBig < 0n || targetIdxBig > 65535n) {
|
|
4348
|
+
continue;
|
|
4349
|
+
}
|
|
4350
|
+
const targetIdx = Number(targetIdxBig);
|
|
3729
4351
|
const price = BigInt(match[3]);
|
|
3730
4352
|
const closedLo = BigInt(match[4]);
|
|
3731
4353
|
const closedHi = BigInt(match[5]);
|
|
@@ -3753,9 +4375,387 @@ async function fetchAdlRankings(apiBase, slab, fetchFn = fetch) {
|
|
|
3753
4375
|
);
|
|
3754
4376
|
}
|
|
3755
4377
|
const json = await res.json();
|
|
4378
|
+
if (typeof json !== "object" || json === null) {
|
|
4379
|
+
throw new Error("fetchAdlRankings: API returned non-object response");
|
|
4380
|
+
}
|
|
4381
|
+
const obj = json;
|
|
4382
|
+
if (!Array.isArray(obj.rankings)) {
|
|
4383
|
+
throw new Error("fetchAdlRankings: API response missing rankings array");
|
|
4384
|
+
}
|
|
4385
|
+
for (const entry of obj.rankings) {
|
|
4386
|
+
if (typeof entry !== "object" || entry === null) {
|
|
4387
|
+
throw new Error("fetchAdlRankings: invalid ranking entry (not an object)");
|
|
4388
|
+
}
|
|
4389
|
+
const r = entry;
|
|
4390
|
+
if (typeof r.idx !== "number" || !Number.isInteger(r.idx) || r.idx < 0) {
|
|
4391
|
+
throw new Error(`fetchAdlRankings: invalid ranking idx: ${r.idx}`);
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
3756
4394
|
return json;
|
|
3757
4395
|
}
|
|
3758
4396
|
|
|
4397
|
+
// src/solana/rpc-pool.ts
|
|
4398
|
+
import {
|
|
4399
|
+
Connection as Connection5
|
|
4400
|
+
} from "@solana/web3.js";
|
|
4401
|
+
async function checkRpcHealth(endpoint, timeoutMs = 5e3) {
|
|
4402
|
+
const conn = new Connection5(endpoint, { commitment: "processed" });
|
|
4403
|
+
const start = performance.now();
|
|
4404
|
+
const timeout = rejectAfter(timeoutMs, `Health probe timed out after ${timeoutMs}ms`);
|
|
4405
|
+
try {
|
|
4406
|
+
const slot = await Promise.race([
|
|
4407
|
+
conn.getSlot("processed"),
|
|
4408
|
+
timeout.promise
|
|
4409
|
+
]);
|
|
4410
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
4411
|
+
return { endpoint, healthy: true, latencyMs, slot };
|
|
4412
|
+
} catch (err) {
|
|
4413
|
+
const latencyMs = Math.round(performance.now() - start);
|
|
4414
|
+
return {
|
|
4415
|
+
endpoint,
|
|
4416
|
+
healthy: false,
|
|
4417
|
+
latencyMs,
|
|
4418
|
+
slot: 0,
|
|
4419
|
+
error: err instanceof Error ? err.message : String(err)
|
|
4420
|
+
};
|
|
4421
|
+
} finally {
|
|
4422
|
+
timeout.cancel();
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
function resolveRetryConfig(cfg) {
|
|
4426
|
+
if (cfg === false) return null;
|
|
4427
|
+
const c = cfg ?? {};
|
|
4428
|
+
return {
|
|
4429
|
+
maxRetries: c.maxRetries ?? 3,
|
|
4430
|
+
baseDelayMs: c.baseDelayMs ?? 500,
|
|
4431
|
+
maxDelayMs: c.maxDelayMs ?? 1e4,
|
|
4432
|
+
jitterFactor: Math.max(0, Math.min(1, c.jitterFactor ?? 0.25)),
|
|
4433
|
+
retryableStatusCodes: c.retryableStatusCodes ?? [429, 502, 503, 504]
|
|
4434
|
+
};
|
|
4435
|
+
}
|
|
4436
|
+
function normalizeEndpoint(ep) {
|
|
4437
|
+
if (typeof ep === "string") return { url: ep };
|
|
4438
|
+
return ep;
|
|
4439
|
+
}
|
|
4440
|
+
function endpointLabel(ep) {
|
|
4441
|
+
if (ep.label) return ep.label;
|
|
4442
|
+
try {
|
|
4443
|
+
return new URL(ep.url).hostname;
|
|
4444
|
+
} catch {
|
|
4445
|
+
return ep.url.slice(0, 40);
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
function isRetryable(err, codes) {
|
|
4449
|
+
if (!err) return false;
|
|
4450
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4451
|
+
for (const code of codes) {
|
|
4452
|
+
if (msg.includes(String(code))) return true;
|
|
4453
|
+
}
|
|
4454
|
+
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")) {
|
|
4455
|
+
return true;
|
|
4456
|
+
}
|
|
4457
|
+
return false;
|
|
4458
|
+
}
|
|
4459
|
+
function computeDelay(attempt, config) {
|
|
4460
|
+
const raw = Math.min(
|
|
4461
|
+
config.baseDelayMs * Math.pow(2, attempt),
|
|
4462
|
+
config.maxDelayMs
|
|
4463
|
+
);
|
|
4464
|
+
const jitter = Math.floor(Math.random() * raw * config.jitterFactor);
|
|
4465
|
+
return raw + jitter;
|
|
4466
|
+
}
|
|
4467
|
+
function rejectAfter(ms, message) {
|
|
4468
|
+
let timer;
|
|
4469
|
+
const promise = new Promise((_, reject) => {
|
|
4470
|
+
timer = setTimeout(() => reject(new Error(message)), ms);
|
|
4471
|
+
});
|
|
4472
|
+
return { promise, cancel: () => clearTimeout(timer) };
|
|
4473
|
+
}
|
|
4474
|
+
function sleep(ms) {
|
|
4475
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4476
|
+
}
|
|
4477
|
+
function redactUrl(raw) {
|
|
4478
|
+
try {
|
|
4479
|
+
const u = new URL(raw);
|
|
4480
|
+
const sensitive = /^(api[-_]?key|access[-_]?token|auth[-_]?token|token|secret|key|password|bearer|credential|jwt)$/i;
|
|
4481
|
+
for (const k of [...u.searchParams.keys()]) {
|
|
4482
|
+
if (sensitive.test(k)) {
|
|
4483
|
+
u.searchParams.set(k, "***");
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
return u.toString();
|
|
4487
|
+
} catch {
|
|
4488
|
+
return raw;
|
|
4489
|
+
}
|
|
4490
|
+
}
|
|
4491
|
+
var RpcPool = class _RpcPool {
|
|
4492
|
+
endpoints;
|
|
4493
|
+
strategy;
|
|
4494
|
+
retryConfig;
|
|
4495
|
+
requestTimeoutMs;
|
|
4496
|
+
verbose;
|
|
4497
|
+
/** Round-robin index tracker. */
|
|
4498
|
+
rrIndex = 0;
|
|
4499
|
+
/** Consecutive failure threshold before marking an endpoint unhealthy. */
|
|
4500
|
+
static UNHEALTHY_THRESHOLD = 3;
|
|
4501
|
+
/** Minimum endpoints before auto-recovery is attempted. */
|
|
4502
|
+
static MIN_HEALTHY = 1;
|
|
4503
|
+
constructor(config) {
|
|
4504
|
+
if (!config.endpoints || config.endpoints.length === 0) {
|
|
4505
|
+
throw new Error("RpcPool: at least one endpoint is required");
|
|
4506
|
+
}
|
|
4507
|
+
this.strategy = config.strategy ?? "failover";
|
|
4508
|
+
this.retryConfig = resolveRetryConfig(config.retry);
|
|
4509
|
+
this.requestTimeoutMs = config.requestTimeoutMs ?? 3e4;
|
|
4510
|
+
this.verbose = config.verbose ?? true;
|
|
4511
|
+
const commitment = config.commitment ?? "confirmed";
|
|
4512
|
+
this.endpoints = config.endpoints.map((raw) => {
|
|
4513
|
+
const ep = normalizeEndpoint(raw);
|
|
4514
|
+
const connConfig = {
|
|
4515
|
+
commitment,
|
|
4516
|
+
...ep.connectionConfig
|
|
4517
|
+
};
|
|
4518
|
+
return {
|
|
4519
|
+
config: ep,
|
|
4520
|
+
connection: new Connection5(ep.url, connConfig),
|
|
4521
|
+
label: endpointLabel(ep),
|
|
4522
|
+
weight: Math.max(1, ep.weight ?? 1),
|
|
4523
|
+
failures: 0,
|
|
4524
|
+
healthy: true,
|
|
4525
|
+
lastLatencyMs: -1
|
|
4526
|
+
};
|
|
4527
|
+
});
|
|
4528
|
+
}
|
|
4529
|
+
// -----------------------------------------------------------------------
|
|
4530
|
+
// Public API
|
|
4531
|
+
// -----------------------------------------------------------------------
|
|
4532
|
+
/**
|
|
4533
|
+
* Execute a function against a pooled connection with automatic retry
|
|
4534
|
+
* and failover.
|
|
4535
|
+
*
|
|
4536
|
+
* @param fn - Async function that receives a `Connection` and returns a result.
|
|
4537
|
+
* @returns The result of `fn`.
|
|
4538
|
+
* @throws The last error if all retries and failovers are exhausted.
|
|
4539
|
+
*
|
|
4540
|
+
* @example
|
|
4541
|
+
* ```ts
|
|
4542
|
+
* const balance = await pool.call(c => c.getBalance(pubkey));
|
|
4543
|
+
* const markets = await pool.call(c => discoverMarkets(c, programId, opts));
|
|
4544
|
+
* ```
|
|
4545
|
+
*/
|
|
4546
|
+
async call(fn) {
|
|
4547
|
+
const maxAttempts = this.retryConfig ? this.retryConfig.maxRetries + 1 : 1;
|
|
4548
|
+
let lastError;
|
|
4549
|
+
const triedEndpoints = /* @__PURE__ */ new Set();
|
|
4550
|
+
const maxTotalIterations = maxAttempts + this.endpoints.length;
|
|
4551
|
+
let totalIterations = 0;
|
|
4552
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4553
|
+
if (++totalIterations > maxTotalIterations) break;
|
|
4554
|
+
const epIdx = this.selectEndpoint(triedEndpoints);
|
|
4555
|
+
if (epIdx === -1) {
|
|
4556
|
+
break;
|
|
4557
|
+
}
|
|
4558
|
+
const ep = this.endpoints[epIdx];
|
|
4559
|
+
const timeout = rejectAfter(this.requestTimeoutMs, `RPC request timed out after ${this.requestTimeoutMs}ms (${ep.label})`);
|
|
4560
|
+
try {
|
|
4561
|
+
const result = await Promise.race([
|
|
4562
|
+
fn(ep.connection),
|
|
4563
|
+
timeout.promise
|
|
4564
|
+
]);
|
|
4565
|
+
timeout.cancel();
|
|
4566
|
+
ep.failures = 0;
|
|
4567
|
+
ep.healthy = true;
|
|
4568
|
+
return result;
|
|
4569
|
+
} catch (err) {
|
|
4570
|
+
timeout.cancel();
|
|
4571
|
+
lastError = err;
|
|
4572
|
+
ep.failures++;
|
|
4573
|
+
if (ep.failures >= _RpcPool.UNHEALTHY_THRESHOLD) {
|
|
4574
|
+
ep.healthy = false;
|
|
4575
|
+
if (this.verbose) {
|
|
4576
|
+
console.warn(
|
|
4577
|
+
`[RpcPool] Endpoint ${ep.label} marked unhealthy after ${ep.failures} consecutive failures`
|
|
4578
|
+
);
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
const retryable = this.retryConfig ? isRetryable(err, this.retryConfig.retryableStatusCodes) : false;
|
|
4582
|
+
if (!retryable) {
|
|
4583
|
+
if (this.strategy === "failover" && this.endpoints.length > 1) {
|
|
4584
|
+
triedEndpoints.add(epIdx);
|
|
4585
|
+
attempt--;
|
|
4586
|
+
if (triedEndpoints.size >= this.endpoints.length) break;
|
|
4587
|
+
continue;
|
|
4588
|
+
}
|
|
4589
|
+
throw err;
|
|
4590
|
+
}
|
|
4591
|
+
if (this.verbose) {
|
|
4592
|
+
console.warn(
|
|
4593
|
+
`[RpcPool] Retryable error on ${ep.label} (attempt ${attempt + 1}/${maxAttempts}):`,
|
|
4594
|
+
err instanceof Error ? err.message : err
|
|
4595
|
+
);
|
|
4596
|
+
}
|
|
4597
|
+
if (this.strategy === "failover" && this.endpoints.length > 1) {
|
|
4598
|
+
triedEndpoints.add(epIdx);
|
|
4599
|
+
}
|
|
4600
|
+
if (attempt < maxAttempts - 1 && this.retryConfig) {
|
|
4601
|
+
const delay = computeDelay(attempt, this.retryConfig);
|
|
4602
|
+
await sleep(delay);
|
|
4603
|
+
}
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
this.maybeRecoverEndpoints();
|
|
4607
|
+
throw lastError ?? new Error("RpcPool: all endpoints exhausted");
|
|
4608
|
+
}
|
|
4609
|
+
/**
|
|
4610
|
+
* Get a raw `Connection` from the current preferred endpoint.
|
|
4611
|
+
* Useful when you need to pass a Connection to external code.
|
|
4612
|
+
*
|
|
4613
|
+
* NOTE: This bypasses retry and failover logic. Prefer `call()`.
|
|
4614
|
+
*
|
|
4615
|
+
* @returns Solana Connection from the current preferred endpoint.
|
|
4616
|
+
*
|
|
4617
|
+
* @example
|
|
4618
|
+
* ```ts
|
|
4619
|
+
* const conn = pool.getConnection();
|
|
4620
|
+
* const balance = await conn.getBalance(pubkey);
|
|
4621
|
+
* ```
|
|
4622
|
+
*/
|
|
4623
|
+
getConnection() {
|
|
4624
|
+
const idx = this.selectEndpoint();
|
|
4625
|
+
if (idx === -1) {
|
|
4626
|
+
this.maybeRecoverEndpoints();
|
|
4627
|
+
return this.endpoints[0].connection;
|
|
4628
|
+
}
|
|
4629
|
+
return this.endpoints[idx].connection;
|
|
4630
|
+
}
|
|
4631
|
+
/**
|
|
4632
|
+
* Run a health check against all endpoints in the pool.
|
|
4633
|
+
*
|
|
4634
|
+
* @param timeoutMs - Per-endpoint probe timeout (default: 5000)
|
|
4635
|
+
* @returns Array of health results, one per endpoint.
|
|
4636
|
+
*
|
|
4637
|
+
* @example
|
|
4638
|
+
* ```ts
|
|
4639
|
+
* const results = await pool.healthCheck();
|
|
4640
|
+
* for (const r of results) {
|
|
4641
|
+
* console.log(`${r.endpoint}: ${r.healthy ? 'UP' : 'DOWN'} (${r.latencyMs}ms, slot ${r.slot})`);
|
|
4642
|
+
* }
|
|
4643
|
+
* ```
|
|
4644
|
+
*/
|
|
4645
|
+
async healthCheck(timeoutMs = 5e3) {
|
|
4646
|
+
const results = await Promise.all(
|
|
4647
|
+
this.endpoints.map(async (ep) => {
|
|
4648
|
+
const result = await checkRpcHealth(ep.config.url, timeoutMs);
|
|
4649
|
+
ep.lastLatencyMs = result.latencyMs;
|
|
4650
|
+
ep.healthy = result.healthy;
|
|
4651
|
+
if (result.healthy) ep.failures = 0;
|
|
4652
|
+
result.endpoint = redactUrl(result.endpoint);
|
|
4653
|
+
return result;
|
|
4654
|
+
})
|
|
4655
|
+
);
|
|
4656
|
+
return results;
|
|
4657
|
+
}
|
|
4658
|
+
/**
|
|
4659
|
+
* Get the number of endpoints in the pool.
|
|
4660
|
+
*/
|
|
4661
|
+
get size() {
|
|
4662
|
+
return this.endpoints.length;
|
|
4663
|
+
}
|
|
4664
|
+
/**
|
|
4665
|
+
* Get the number of currently healthy endpoints.
|
|
4666
|
+
*/
|
|
4667
|
+
get healthyCount() {
|
|
4668
|
+
return this.endpoints.filter((ep) => ep.healthy).length;
|
|
4669
|
+
}
|
|
4670
|
+
/**
|
|
4671
|
+
* Get endpoint labels and their current status.
|
|
4672
|
+
*
|
|
4673
|
+
* @returns Array of `{ label, url, healthy, failures, lastLatencyMs }`.
|
|
4674
|
+
*/
|
|
4675
|
+
status() {
|
|
4676
|
+
return this.endpoints.map((ep) => ({
|
|
4677
|
+
label: ep.label,
|
|
4678
|
+
url: redactUrl(ep.config.url),
|
|
4679
|
+
healthy: ep.healthy,
|
|
4680
|
+
failures: ep.failures,
|
|
4681
|
+
lastLatencyMs: ep.lastLatencyMs
|
|
4682
|
+
}));
|
|
4683
|
+
}
|
|
4684
|
+
// -----------------------------------------------------------------------
|
|
4685
|
+
// Internals
|
|
4686
|
+
// -----------------------------------------------------------------------
|
|
4687
|
+
/**
|
|
4688
|
+
* Select the next endpoint based on strategy.
|
|
4689
|
+
* Returns -1 if no endpoint is available.
|
|
4690
|
+
*/
|
|
4691
|
+
selectEndpoint(exclude) {
|
|
4692
|
+
const healthy = this.endpoints.map((ep, i) => ({ ep, i })).filter(({ ep, i }) => ep.healthy && !exclude?.has(i));
|
|
4693
|
+
if (healthy.length === 0) {
|
|
4694
|
+
const remaining = this.endpoints.map((_, i) => i).filter((i) => !exclude?.has(i));
|
|
4695
|
+
return remaining.length > 0 ? remaining[0] : -1;
|
|
4696
|
+
}
|
|
4697
|
+
if (this.strategy === "failover") {
|
|
4698
|
+
return healthy[0].i;
|
|
4699
|
+
}
|
|
4700
|
+
const totalWeight = healthy.reduce((sum, { ep }) => sum + ep.weight, 0);
|
|
4701
|
+
this.rrIndex = (this.rrIndex + 1) % totalWeight;
|
|
4702
|
+
let cumulative = 0;
|
|
4703
|
+
for (const { ep, i } of healthy) {
|
|
4704
|
+
cumulative += ep.weight;
|
|
4705
|
+
if (this.rrIndex < cumulative) return i;
|
|
4706
|
+
}
|
|
4707
|
+
return healthy[healthy.length - 1].i;
|
|
4708
|
+
}
|
|
4709
|
+
/**
|
|
4710
|
+
* If all endpoints are unhealthy, reset them so we at least try again.
|
|
4711
|
+
*/
|
|
4712
|
+
maybeRecoverEndpoints() {
|
|
4713
|
+
const healthyCount = this.endpoints.filter((ep) => ep.healthy).length;
|
|
4714
|
+
if (healthyCount < _RpcPool.MIN_HEALTHY) {
|
|
4715
|
+
if (this.verbose) {
|
|
4716
|
+
console.warn("[RpcPool] All endpoints unhealthy \u2014 resetting for recovery");
|
|
4717
|
+
}
|
|
4718
|
+
for (const ep of this.endpoints) {
|
|
4719
|
+
ep.healthy = true;
|
|
4720
|
+
ep.failures = 0;
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
}
|
|
4724
|
+
};
|
|
4725
|
+
async function withRetry(fn, config) {
|
|
4726
|
+
const resolved = resolveRetryConfig(config) ?? {
|
|
4727
|
+
maxRetries: 3,
|
|
4728
|
+
baseDelayMs: 500,
|
|
4729
|
+
maxDelayMs: 1e4,
|
|
4730
|
+
jitterFactor: 0.25,
|
|
4731
|
+
retryableStatusCodes: [429, 502, 503, 504]
|
|
4732
|
+
};
|
|
4733
|
+
let lastError;
|
|
4734
|
+
const maxAttempts = resolved.maxRetries + 1;
|
|
4735
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
4736
|
+
try {
|
|
4737
|
+
return await fn();
|
|
4738
|
+
} catch (err) {
|
|
4739
|
+
lastError = err;
|
|
4740
|
+
if (!isRetryable(err, resolved.retryableStatusCodes)) {
|
|
4741
|
+
throw err;
|
|
4742
|
+
}
|
|
4743
|
+
if (attempt < maxAttempts - 1) {
|
|
4744
|
+
const delay = computeDelay(attempt, resolved);
|
|
4745
|
+
await sleep(delay);
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
throw lastError ?? new Error("withRetry: all attempts exhausted");
|
|
4750
|
+
}
|
|
4751
|
+
var _internal = {
|
|
4752
|
+
isRetryable,
|
|
4753
|
+
computeDelay,
|
|
4754
|
+
resolveRetryConfig,
|
|
4755
|
+
normalizeEndpoint,
|
|
4756
|
+
endpointLabel
|
|
4757
|
+
};
|
|
4758
|
+
|
|
3759
4759
|
// src/runtime/tx.ts
|
|
3760
4760
|
import {
|
|
3761
4761
|
TransactionInstruction as TransactionInstruction2,
|
|
@@ -3907,6 +4907,139 @@ function formatResult(result, jsonMode) {
|
|
|
3907
4907
|
return lines.join("\n");
|
|
3908
4908
|
}
|
|
3909
4909
|
|
|
4910
|
+
// src/runtime/lighthouse.ts
|
|
4911
|
+
import { PublicKey as PublicKey13, Transaction as Transaction2 } from "@solana/web3.js";
|
|
4912
|
+
var LIGHTHOUSE_PROGRAM_ID = new PublicKey13(
|
|
4913
|
+
"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95"
|
|
4914
|
+
);
|
|
4915
|
+
var LIGHTHOUSE_PROGRAM_ID_STR2 = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
|
|
4916
|
+
var LIGHTHOUSE_CONSTRAINT_ADDRESS = 6400;
|
|
4917
|
+
var LIGHTHOUSE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
4918
|
+
6e3,
|
|
4919
|
+
// InstructionMissing
|
|
4920
|
+
6001,
|
|
4921
|
+
// InstructionFallbackNotFound
|
|
4922
|
+
6002,
|
|
4923
|
+
// InstructionDidNotDeserialize
|
|
4924
|
+
6003,
|
|
4925
|
+
// InstructionDidNotSerialize
|
|
4926
|
+
6016,
|
|
4927
|
+
// IdlInstructionStub
|
|
4928
|
+
6032,
|
|
4929
|
+
// ConstraintMut
|
|
4930
|
+
6033,
|
|
4931
|
+
// ConstraintHasOne
|
|
4932
|
+
6034,
|
|
4933
|
+
// ConstraintSigner
|
|
4934
|
+
6035,
|
|
4935
|
+
// ConstraintRaw
|
|
4936
|
+
6036,
|
|
4937
|
+
// ConstraintOwner
|
|
4938
|
+
6037,
|
|
4939
|
+
// ConstraintRentExempt
|
|
4940
|
+
6038,
|
|
4941
|
+
// ConstraintSeeds
|
|
4942
|
+
6039,
|
|
4943
|
+
// ConstraintExecutable
|
|
4944
|
+
6040,
|
|
4945
|
+
// ConstraintState
|
|
4946
|
+
6041,
|
|
4947
|
+
// ConstraintAssociated
|
|
4948
|
+
6042,
|
|
4949
|
+
// ConstraintAssociatedInit
|
|
4950
|
+
6043,
|
|
4951
|
+
// ConstraintClose
|
|
4952
|
+
6400
|
|
4953
|
+
// ConstraintAddress (the one we hit most often)
|
|
4954
|
+
]);
|
|
4955
|
+
function isLighthouseInstruction(ix) {
|
|
4956
|
+
return ix.programId.equals(LIGHTHOUSE_PROGRAM_ID);
|
|
4957
|
+
}
|
|
4958
|
+
function isLighthouseError(error) {
|
|
4959
|
+
const msg = extractErrorMessage(error);
|
|
4960
|
+
if (!msg) return false;
|
|
4961
|
+
if (msg.includes(LIGHTHOUSE_PROGRAM_ID_STR2)) return true;
|
|
4962
|
+
if (/custom\s+program\s+error:\s*0x1900\b/i.test(msg)) return true;
|
|
4963
|
+
if (/"Custom"\s*:\s*6400\b/.test(msg) && /InstructionError/i.test(msg)) return true;
|
|
4964
|
+
return false;
|
|
4965
|
+
}
|
|
4966
|
+
function isLighthouseFailureInLogs(logs) {
|
|
4967
|
+
if (!Array.isArray(logs)) return false;
|
|
4968
|
+
let insideLighthouse = false;
|
|
4969
|
+
for (const line of logs) {
|
|
4970
|
+
if (typeof line !== "string") continue;
|
|
4971
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} invoke`)) {
|
|
4972
|
+
insideLighthouse = true;
|
|
4973
|
+
continue;
|
|
4974
|
+
}
|
|
4975
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} success`)) {
|
|
4976
|
+
insideLighthouse = false;
|
|
4977
|
+
continue;
|
|
4978
|
+
}
|
|
4979
|
+
if (insideLighthouse && /failed/i.test(line)) {
|
|
4980
|
+
return true;
|
|
4981
|
+
}
|
|
4982
|
+
if (line.includes(`Program ${LIGHTHOUSE_PROGRAM_ID_STR2} failed`)) {
|
|
4983
|
+
return true;
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
return false;
|
|
4987
|
+
}
|
|
4988
|
+
function stripLighthouseInstructions(instructions, percolatorProgramId) {
|
|
4989
|
+
if (percolatorProgramId) {
|
|
4990
|
+
const hasPercolatorIx = instructions.some(
|
|
4991
|
+
(ix) => ix.programId.equals(percolatorProgramId)
|
|
4992
|
+
);
|
|
4993
|
+
if (!hasPercolatorIx) {
|
|
4994
|
+
return instructions;
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
return instructions.filter((ix) => !isLighthouseInstruction(ix));
|
|
4998
|
+
}
|
|
4999
|
+
function stripLighthouseFromTransaction(transaction, percolatorProgramId) {
|
|
5000
|
+
if (percolatorProgramId) {
|
|
5001
|
+
const hasPercolatorIx = transaction.instructions.some(
|
|
5002
|
+
(ix) => ix.programId.equals(percolatorProgramId)
|
|
5003
|
+
);
|
|
5004
|
+
if (!hasPercolatorIx) return transaction;
|
|
5005
|
+
}
|
|
5006
|
+
const hasLighthouse = transaction.instructions.some(isLighthouseInstruction);
|
|
5007
|
+
if (!hasLighthouse) return transaction;
|
|
5008
|
+
const clean = new Transaction2();
|
|
5009
|
+
clean.recentBlockhash = transaction.recentBlockhash;
|
|
5010
|
+
clean.feePayer = transaction.feePayer;
|
|
5011
|
+
for (const ix of transaction.instructions) {
|
|
5012
|
+
if (!isLighthouseInstruction(ix)) {
|
|
5013
|
+
clean.add(ix);
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
return clean;
|
|
5017
|
+
}
|
|
5018
|
+
function countLighthouseInstructions(ixsOrTx) {
|
|
5019
|
+
const instructions = Array.isArray(ixsOrTx) ? ixsOrTx : ixsOrTx.instructions;
|
|
5020
|
+
return instructions.filter(isLighthouseInstruction).length;
|
|
5021
|
+
}
|
|
5022
|
+
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";
|
|
5023
|
+
function classifyLighthouseError(error) {
|
|
5024
|
+
if (isLighthouseError(error)) {
|
|
5025
|
+
return LIGHTHOUSE_USER_MESSAGE;
|
|
5026
|
+
}
|
|
5027
|
+
return null;
|
|
5028
|
+
}
|
|
5029
|
+
function extractErrorMessage(error) {
|
|
5030
|
+
if (!error) return null;
|
|
5031
|
+
if (typeof error === "string") return error;
|
|
5032
|
+
if (error instanceof Error) return error.message;
|
|
5033
|
+
if (typeof error === "object" && "message" in error) {
|
|
5034
|
+
return String(error.message);
|
|
5035
|
+
}
|
|
5036
|
+
try {
|
|
5037
|
+
return JSON.stringify(error);
|
|
5038
|
+
} catch {
|
|
5039
|
+
return null;
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5042
|
+
|
|
3910
5043
|
// src/math/trading.ts
|
|
3911
5044
|
function computeMarkPnl(positionSize, entryPrice, oraclePrice) {
|
|
3912
5045
|
if (positionSize === 0n || oraclePrice === 0n) return 0n;
|
|
@@ -3954,9 +5087,20 @@ function computeFeeSplit(totalFee, config) {
|
|
|
3954
5087
|
if (config.lpBps === 0n && config.protocolBps === 0n && config.creatorBps === 0n) {
|
|
3955
5088
|
return [totalFee, 0n, 0n];
|
|
3956
5089
|
}
|
|
5090
|
+
const totalBps = config.lpBps + config.protocolBps + config.creatorBps;
|
|
5091
|
+
if (totalBps !== 10000n) {
|
|
5092
|
+
throw new Error(
|
|
5093
|
+
`Fee split must equal exactly 10000 bps (100%): lpBps=${config.lpBps} + protocolBps=${config.protocolBps} + creatorBps=${config.creatorBps} = ${totalBps}`
|
|
5094
|
+
);
|
|
5095
|
+
}
|
|
3957
5096
|
const lp = totalFee * config.lpBps / 10000n;
|
|
3958
5097
|
const protocol = totalFee * config.protocolBps / 10000n;
|
|
3959
5098
|
const creator = totalFee - lp - protocol;
|
|
5099
|
+
if (creator < 0n) {
|
|
5100
|
+
throw new Error(
|
|
5101
|
+
`Internal error: creator fee is negative (${creator}). This should not happen if lpBps + protocolBps + creatorBps === 10000.`
|
|
5102
|
+
);
|
|
5103
|
+
}
|
|
3960
5104
|
return [lp, protocol, creator];
|
|
3961
5105
|
}
|
|
3962
5106
|
function computePnlPercent(pnlTokens, capital) {
|
|
@@ -3971,8 +5115,17 @@ function computePnlPercent(pnlTokens, capital) {
|
|
|
3971
5115
|
}
|
|
3972
5116
|
function computeEstimatedEntryPrice(oracleE6, tradingFeeBps, direction) {
|
|
3973
5117
|
if (oracleE6 === 0n) return 0n;
|
|
5118
|
+
if (tradingFeeBps < 0n) {
|
|
5119
|
+
throw new Error(`computeEstimatedEntryPrice: tradingFeeBps must be non-negative, got ${tradingFeeBps}`);
|
|
5120
|
+
}
|
|
3974
5121
|
const feeImpact = oracleE6 * tradingFeeBps / 10000n;
|
|
3975
|
-
|
|
5122
|
+
const result = direction === "long" ? oracleE6 + feeImpact : oracleE6 - feeImpact;
|
|
5123
|
+
if (result <= 0n) {
|
|
5124
|
+
throw new Error(
|
|
5125
|
+
`computeEstimatedEntryPrice: result ${result} is non-positive (tradingFeeBps=${tradingFeeBps} too high for oracle=${oracleE6})`
|
|
5126
|
+
);
|
|
5127
|
+
}
|
|
5128
|
+
return result;
|
|
3976
5129
|
}
|
|
3977
5130
|
var MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
|
|
3978
5131
|
var MIN_SAFE_BIGINT = BigInt(-Number.MAX_SAFE_INTEGER);
|
|
@@ -3993,7 +5146,12 @@ function computeMaxLeverage(initialMarginBps) {
|
|
|
3993
5146
|
if (initialMarginBps <= 0n) {
|
|
3994
5147
|
throw new Error("computeMaxLeverage: initialMarginBps must be positive");
|
|
3995
5148
|
}
|
|
3996
|
-
|
|
5149
|
+
const scaledResult = 10000n * 1000000n / initialMarginBps;
|
|
5150
|
+
return Number(scaledResult) / 1e6;
|
|
5151
|
+
}
|
|
5152
|
+
function computeMaxWithdrawable(capital, pnl, reservedPnl) {
|
|
5153
|
+
const maturedPnl = pnl - reservedPnl;
|
|
5154
|
+
return capital + (maturedPnl > 0n ? maturedPnl : 0n);
|
|
3997
5155
|
}
|
|
3998
5156
|
|
|
3999
5157
|
// src/math/warmup.ts
|
|
@@ -4005,6 +5163,9 @@ function computeWarmupUnlockedCapital(totalCapital, currentSlot, warmupStartSlot
|
|
|
4005
5163
|
return totalCapital * elapsed / warmupPeriodSlots;
|
|
4006
5164
|
}
|
|
4007
5165
|
function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
5166
|
+
if (initialMarginBps <= 0n) {
|
|
5167
|
+
throw new Error("computeWarmupLeverageCap: initialMarginBps must be positive");
|
|
5168
|
+
}
|
|
4008
5169
|
const maxLev = computeMaxLeverage(initialMarginBps);
|
|
4009
5170
|
if (warmupPeriodSlots === 0n || warmupStartSlot === 0n) return maxLev;
|
|
4010
5171
|
if (totalCapital <= 0n) return 1;
|
|
@@ -4015,7 +5176,14 @@ function computeWarmupLeverageCap(initialMarginBps, totalCapital, currentSlot, w
|
|
|
4015
5176
|
warmupPeriodSlots
|
|
4016
5177
|
);
|
|
4017
5178
|
if (unlocked <= 0n) return 1;
|
|
4018
|
-
const
|
|
5179
|
+
const scaledResult = BigInt(maxLev) * unlocked / totalCapital;
|
|
5180
|
+
if (scaledResult > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5181
|
+
console.warn(
|
|
5182
|
+
`[computeWarmupLeverageCap] Warning: effective leverage ${scaledResult} exceeds MAX_SAFE_INTEGER, returning MAX_SAFE_INTEGER as a safety bound`
|
|
5183
|
+
);
|
|
5184
|
+
return Number.MAX_SAFE_INTEGER;
|
|
5185
|
+
}
|
|
5186
|
+
const effectiveLev = Number(scaledResult);
|
|
4019
5187
|
return Math.max(1, effectiveLev);
|
|
4020
5188
|
}
|
|
4021
5189
|
function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlot, warmupStartSlot, warmupPeriodSlots) {
|
|
@@ -4028,9 +5196,40 @@ function computeWarmupMaxPositionSize(initialMarginBps, totalCapital, currentSlo
|
|
|
4028
5196
|
);
|
|
4029
5197
|
return unlocked * BigInt(maxLev);
|
|
4030
5198
|
}
|
|
5199
|
+
function computeWarmupProgress(currentSlot, warmupStartedAtSlot, warmupPeriodSlots, pnl, reservedPnl) {
|
|
5200
|
+
if (warmupPeriodSlots === 0n || warmupStartedAtSlot === 0n) {
|
|
5201
|
+
return {
|
|
5202
|
+
maturedPnl: pnl > 0n ? pnl : 0n,
|
|
5203
|
+
reservedPnl: 0n,
|
|
5204
|
+
progressBps: 10000n,
|
|
5205
|
+
// 100%
|
|
5206
|
+
slotsRemaining: 0n
|
|
5207
|
+
};
|
|
5208
|
+
}
|
|
5209
|
+
const elapsed = currentSlot >= warmupStartedAtSlot ? currentSlot - warmupStartedAtSlot : 0n;
|
|
5210
|
+
if (elapsed >= warmupPeriodSlots) {
|
|
5211
|
+
return {
|
|
5212
|
+
maturedPnl: pnl > 0n ? pnl : 0n,
|
|
5213
|
+
reservedPnl: 0n,
|
|
5214
|
+
progressBps: 10000n,
|
|
5215
|
+
// 100%
|
|
5216
|
+
slotsRemaining: 0n
|
|
5217
|
+
};
|
|
5218
|
+
}
|
|
5219
|
+
const progressBps = elapsed * 10000n / warmupPeriodSlots;
|
|
5220
|
+
const slotsRemaining = warmupPeriodSlots - elapsed;
|
|
5221
|
+
const maturedPnl = pnl > 0n ? pnl * progressBps / 10000n : 0n;
|
|
5222
|
+
const locked = reservedPnl > 0n ? reservedPnl : 0n;
|
|
5223
|
+
return {
|
|
5224
|
+
maturedPnl,
|
|
5225
|
+
reservedPnl: locked,
|
|
5226
|
+
progressBps,
|
|
5227
|
+
slotsRemaining
|
|
5228
|
+
};
|
|
5229
|
+
}
|
|
4031
5230
|
|
|
4032
5231
|
// src/validation.ts
|
|
4033
|
-
import { PublicKey as
|
|
5232
|
+
import { PublicKey as PublicKey14 } from "@solana/web3.js";
|
|
4034
5233
|
var U16_MAX = 65535;
|
|
4035
5234
|
var U64_MAX = BigInt("18446744073709551615");
|
|
4036
5235
|
var I64_MIN = BigInt("-9223372036854775808");
|
|
@@ -4060,7 +5259,7 @@ var ValidationError = class extends Error {
|
|
|
4060
5259
|
};
|
|
4061
5260
|
function validatePublicKey(value, field) {
|
|
4062
5261
|
try {
|
|
4063
|
-
return new
|
|
5262
|
+
return new PublicKey14(value);
|
|
4064
5263
|
} catch {
|
|
4065
5264
|
throw new ValidationError(
|
|
4066
5265
|
field,
|
|
@@ -4077,18 +5276,20 @@ function validateIndex(value, field) {
|
|
|
4077
5276
|
`must be <= ${U16_MAX} (u16 max), got ${t}`
|
|
4078
5277
|
);
|
|
4079
5278
|
}
|
|
5279
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5280
|
+
throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
|
|
5281
|
+
}
|
|
4080
5282
|
return Number(bi);
|
|
4081
5283
|
}
|
|
4082
5284
|
function validateAmount(value, field) {
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
num = BigInt(value);
|
|
4086
|
-
} catch {
|
|
5285
|
+
const t = value.trim();
|
|
5286
|
+
if (!/^(0|[1-9]\d*)$/.test(t)) {
|
|
4087
5287
|
throw new ValidationError(
|
|
4088
5288
|
field,
|
|
4089
|
-
`"${value}" is not a valid
|
|
5289
|
+
`"${value}" is not a valid non-negative integer. Use decimal digits only.`
|
|
4090
5290
|
);
|
|
4091
5291
|
}
|
|
5292
|
+
const num = BigInt(t);
|
|
4092
5293
|
if (num < 0n) {
|
|
4093
5294
|
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
4094
5295
|
}
|
|
@@ -4101,15 +5302,14 @@ function validateAmount(value, field) {
|
|
|
4101
5302
|
return num;
|
|
4102
5303
|
}
|
|
4103
5304
|
function validateU128(value, field) {
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
num = BigInt(value);
|
|
4107
|
-
} catch {
|
|
5305
|
+
const t = value.trim();
|
|
5306
|
+
if (!/^(0|[1-9]\d*)$/.test(t)) {
|
|
4108
5307
|
throw new ValidationError(
|
|
4109
5308
|
field,
|
|
4110
|
-
`"${value}" is not a valid
|
|
5309
|
+
`"${value}" is not a valid non-negative integer. Use decimal digits only.`
|
|
4111
5310
|
);
|
|
4112
5311
|
}
|
|
5312
|
+
const num = BigInt(t);
|
|
4113
5313
|
if (num < 0n) {
|
|
4114
5314
|
throw new ValidationError(field, `must be non-negative, got ${num}`);
|
|
4115
5315
|
}
|
|
@@ -4122,15 +5322,14 @@ function validateU128(value, field) {
|
|
|
4122
5322
|
return num;
|
|
4123
5323
|
}
|
|
4124
5324
|
function validateI64(value, field) {
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
num = BigInt(value);
|
|
4128
|
-
} catch {
|
|
5325
|
+
const t = value.trim();
|
|
5326
|
+
if (!/^-?(0|[1-9]\d*)$/.test(t)) {
|
|
4129
5327
|
throw new ValidationError(
|
|
4130
5328
|
field,
|
|
4131
|
-
`"${value}" is not a valid
|
|
5329
|
+
`"${value}" is not a valid integer. Use decimal digits only, with optional leading minus.`
|
|
4132
5330
|
);
|
|
4133
5331
|
}
|
|
5332
|
+
const num = BigInt(t);
|
|
4134
5333
|
if (num < I64_MIN) {
|
|
4135
5334
|
throw new ValidationError(
|
|
4136
5335
|
field,
|
|
@@ -4146,15 +5345,14 @@ function validateI64(value, field) {
|
|
|
4146
5345
|
return num;
|
|
4147
5346
|
}
|
|
4148
5347
|
function validateI128(value, field) {
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
num = BigInt(value);
|
|
4152
|
-
} catch {
|
|
5348
|
+
const t = value.trim();
|
|
5349
|
+
if (!/^-?(0|[1-9]\d*)$/.test(t)) {
|
|
4153
5350
|
throw new ValidationError(
|
|
4154
5351
|
field,
|
|
4155
|
-
`"${value}" is not a valid
|
|
5352
|
+
`"${value}" is not a valid integer. Use decimal digits only, with optional leading minus.`
|
|
4156
5353
|
);
|
|
4157
5354
|
}
|
|
5355
|
+
const num = BigInt(t);
|
|
4158
5356
|
if (num < I128_MIN) {
|
|
4159
5357
|
throw new ValidationError(
|
|
4160
5358
|
field,
|
|
@@ -4178,6 +5376,9 @@ function validateBps(value, field) {
|
|
|
4178
5376
|
`must be <= 10000 (100%), got ${t}`
|
|
4179
5377
|
);
|
|
4180
5378
|
}
|
|
5379
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5380
|
+
throw new ValidationError(field, `internal error: bps value exceeds MAX_SAFE_INTEGER`);
|
|
5381
|
+
}
|
|
4181
5382
|
return Number(bi);
|
|
4182
5383
|
}
|
|
4183
5384
|
function validateU64(value, field) {
|
|
@@ -4192,6 +5393,9 @@ function validateU16(value, field) {
|
|
|
4192
5393
|
`must be <= ${U16_MAX} (u16 max), got ${t}`
|
|
4193
5394
|
);
|
|
4194
5395
|
}
|
|
5396
|
+
if (bi > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
5397
|
+
throw new ValidationError(field, `internal error: u16 value exceeds MAX_SAFE_INTEGER`);
|
|
5398
|
+
}
|
|
4195
5399
|
return Number(bi);
|
|
4196
5400
|
}
|
|
4197
5401
|
|
|
@@ -4242,7 +5446,9 @@ function parseDexScreenerPairs(json) {
|
|
|
4242
5446
|
else if (liquidity > 1e4) confidence = 60;
|
|
4243
5447
|
else if (liquidity > 1e3) confidence = 45;
|
|
4244
5448
|
const priceUsd = pair.priceUsd;
|
|
4245
|
-
const
|
|
5449
|
+
const rawPrice = typeof priceUsd === "string" || typeof priceUsd === "number" ? parseFloat(String(priceUsd)) : NaN;
|
|
5450
|
+
if (!Number.isFinite(rawPrice) || rawPrice <= 0) continue;
|
|
5451
|
+
const price = rawPrice;
|
|
4246
5452
|
let baseSym = "?";
|
|
4247
5453
|
let quoteSym = "?";
|
|
4248
5454
|
if (isRecord(pair.baseToken) && typeof pair.baseToken.symbol === "string") {
|
|
@@ -4273,8 +5479,8 @@ function parseJupiterMintEntry(json, mint) {
|
|
|
4273
5479
|
if (!isRecord(row)) return null;
|
|
4274
5480
|
const rawPrice = row.price;
|
|
4275
5481
|
if (rawPrice === void 0 || rawPrice === null) return null;
|
|
4276
|
-
const price = parseFloat(String(rawPrice))
|
|
4277
|
-
if (price <= 0) return null;
|
|
5482
|
+
const price = parseFloat(String(rawPrice));
|
|
5483
|
+
if (!Number.isFinite(price) || price <= 0) return null;
|
|
4278
5484
|
let mintSymbol = "?";
|
|
4279
5485
|
if (typeof row.mintSymbol === "string") mintSymbol = row.mintSymbol;
|
|
4280
5486
|
return { price, mintSymbol };
|
|
@@ -4340,10 +5546,17 @@ async function fetchDexSources(mint, signal) {
|
|
|
4340
5546
|
headers: { "User-Agent": "percolator/1.0" }
|
|
4341
5547
|
}
|
|
4342
5548
|
);
|
|
4343
|
-
if (!resp.ok)
|
|
5549
|
+
if (!resp.ok) {
|
|
5550
|
+
console.debug(`[fetchDexSources] HTTP ${resp.status} for mint ${mint}`);
|
|
5551
|
+
return [];
|
|
5552
|
+
}
|
|
4344
5553
|
const json = await resp.json();
|
|
4345
5554
|
return parseDexScreenerPairs(json);
|
|
4346
|
-
} catch {
|
|
5555
|
+
} catch (err) {
|
|
5556
|
+
console.warn(
|
|
5557
|
+
`[fetchDexSources] Error fetching DexScreener data for mint ${mint}:`,
|
|
5558
|
+
err instanceof Error ? err.message : String(err)
|
|
5559
|
+
);
|
|
4347
5560
|
return [];
|
|
4348
5561
|
}
|
|
4349
5562
|
}
|
|
@@ -4354,7 +5567,7 @@ function lookupPythSource(mint) {
|
|
|
4354
5567
|
type: "pyth",
|
|
4355
5568
|
address: entry.feedId,
|
|
4356
5569
|
pairLabel: `${entry.symbol} / USD (Pyth)`,
|
|
4357
|
-
liquidity:
|
|
5570
|
+
liquidity: Number.MAX_SAFE_INTEGER,
|
|
4358
5571
|
// Pyth is considered deep liquidity
|
|
4359
5572
|
price: 0,
|
|
4360
5573
|
// We don't fetch live price here; caller can enrich
|
|
@@ -4371,10 +5584,16 @@ async function fetchJupiterSource(mint, signal) {
|
|
|
4371
5584
|
headers: { "User-Agent": "percolator/1.0" }
|
|
4372
5585
|
}
|
|
4373
5586
|
);
|
|
4374
|
-
if (!resp.ok)
|
|
5587
|
+
if (!resp.ok) {
|
|
5588
|
+
console.debug(`[fetchJupiterSource] HTTP ${resp.status} for mint ${mint}`);
|
|
5589
|
+
return null;
|
|
5590
|
+
}
|
|
4375
5591
|
const json = await resp.json();
|
|
4376
5592
|
const row = parseJupiterMintEntry(json, mint);
|
|
4377
|
-
if (!row)
|
|
5593
|
+
if (!row) {
|
|
5594
|
+
console.debug(`[fetchJupiterSource] No price data from Jupiter for mint ${mint}`);
|
|
5595
|
+
return null;
|
|
5596
|
+
}
|
|
4378
5597
|
return {
|
|
4379
5598
|
type: "jupiter",
|
|
4380
5599
|
address: mint,
|
|
@@ -4385,7 +5604,11 @@ async function fetchJupiterSource(mint, signal) {
|
|
|
4385
5604
|
confidence: 40
|
|
4386
5605
|
// Fallback — lower confidence
|
|
4387
5606
|
};
|
|
4388
|
-
} catch {
|
|
5607
|
+
} catch (err) {
|
|
5608
|
+
console.warn(
|
|
5609
|
+
`[fetchJupiterSource] Error fetching Jupiter data for mint ${mint}:`,
|
|
5610
|
+
err instanceof Error ? err.message : String(err)
|
|
5611
|
+
);
|
|
4389
5612
|
return null;
|
|
4390
5613
|
}
|
|
4391
5614
|
}
|
|
@@ -4400,8 +5623,20 @@ async function resolvePrice(mint, signal, options) {
|
|
|
4400
5623
|
const pythSource = lookupPythSource(mint);
|
|
4401
5624
|
const allSources = [];
|
|
4402
5625
|
if (pythSource) {
|
|
4403
|
-
const
|
|
4404
|
-
|
|
5626
|
+
const dexPrice = dexSources[0]?.price ?? 0;
|
|
5627
|
+
const jupPrice = jupiterSource?.price ?? 0;
|
|
5628
|
+
if (dexPrice > 0 && jupPrice > 0) {
|
|
5629
|
+
const mid = (dexPrice + jupPrice) / 2;
|
|
5630
|
+
const deviation = Math.abs(dexPrice - jupPrice) / mid;
|
|
5631
|
+
if (deviation > 0.5) {
|
|
5632
|
+
pythSource.price = 0;
|
|
5633
|
+
pythSource.confidence = 20;
|
|
5634
|
+
} else {
|
|
5635
|
+
pythSource.price = mid;
|
|
5636
|
+
}
|
|
5637
|
+
} else {
|
|
5638
|
+
pythSource.price = dexPrice || jupPrice || 0;
|
|
5639
|
+
}
|
|
4405
5640
|
allSources.push(pythSource);
|
|
4406
5641
|
}
|
|
4407
5642
|
allSources.push(...dexSources);
|
|
@@ -4426,13 +5661,12 @@ export {
|
|
|
4426
5661
|
ACCOUNTS_CLOSE_ACCOUNT,
|
|
4427
5662
|
ACCOUNTS_CLOSE_SLAB,
|
|
4428
5663
|
ACCOUNTS_CLOSE_STALE_SLABS,
|
|
4429
|
-
ACCOUNTS_CREATE_INSURANCE_MINT,
|
|
4430
5664
|
ACCOUNTS_DEPOSIT_COLLATERAL,
|
|
4431
|
-
ACCOUNTS_DEPOSIT_INSURANCE_LP,
|
|
4432
5665
|
ACCOUNTS_EXECUTE_ADL,
|
|
4433
5666
|
ACCOUNTS_FUND_MARKET_INSURANCE,
|
|
4434
5667
|
ACCOUNTS_INIT_LP,
|
|
4435
5668
|
ACCOUNTS_INIT_MARKET,
|
|
5669
|
+
ACCOUNTS_INIT_MATCHER_CTX,
|
|
4436
5670
|
ACCOUNTS_INIT_USER,
|
|
4437
5671
|
ACCOUNTS_KEEPER_CRANK,
|
|
4438
5672
|
ACCOUNTS_LIQUIDATE_AT_ORACLE,
|
|
@@ -4461,20 +5695,26 @@ export {
|
|
|
4461
5695
|
ACCOUNTS_UPDATE_CONFIG,
|
|
4462
5696
|
ACCOUNTS_WITHDRAW_COLLATERAL,
|
|
4463
5697
|
ACCOUNTS_WITHDRAW_INSURANCE,
|
|
4464
|
-
ACCOUNTS_WITHDRAW_INSURANCE_LP,
|
|
4465
5698
|
AccountKind,
|
|
4466
5699
|
CHAINLINK_ANSWER_OFFSET,
|
|
4467
5700
|
CHAINLINK_DECIMALS_OFFSET,
|
|
4468
5701
|
CHAINLINK_MIN_SIZE,
|
|
5702
|
+
CHAINLINK_TIMESTAMP_OFFSET,
|
|
4469
5703
|
CREATOR_LOCK_SEED,
|
|
4470
5704
|
CTX_VAMM_OFFSET,
|
|
4471
5705
|
DEFAULT_OI_RAMP_SLOTS,
|
|
4472
5706
|
ENGINE_MARK_PRICE_OFF,
|
|
4473
5707
|
ENGINE_OFF,
|
|
4474
5708
|
IX_TAG,
|
|
5709
|
+
LIGHTHOUSE_CONSTRAINT_ADDRESS,
|
|
5710
|
+
LIGHTHOUSE_ERROR_CODES,
|
|
5711
|
+
LIGHTHOUSE_PROGRAM_ID,
|
|
5712
|
+
LIGHTHOUSE_PROGRAM_ID_STR2 as LIGHTHOUSE_PROGRAM_ID_STR,
|
|
5713
|
+
LIGHTHOUSE_USER_MESSAGE,
|
|
4475
5714
|
MARK_PRICE_EMA_ALPHA_E6,
|
|
4476
5715
|
MARK_PRICE_EMA_WINDOW_SLOTS,
|
|
4477
5716
|
MAX_DECIMALS,
|
|
5717
|
+
MAX_ORACLE_PRICE,
|
|
4478
5718
|
METEORA_DLMM_PROGRAM_ID,
|
|
4479
5719
|
ORACLE_PHASE_GROWING,
|
|
4480
5720
|
ORACLE_PHASE_MATURE,
|
|
@@ -4492,9 +5732,11 @@ export {
|
|
|
4492
5732
|
RAMP_START_BPS,
|
|
4493
5733
|
RAYDIUM_CLMM_PROGRAM_ID,
|
|
4494
5734
|
RENOUNCE_ADMIN_CONFIRMATION,
|
|
5735
|
+
RpcPool,
|
|
4495
5736
|
SLAB_TIERS,
|
|
4496
5737
|
SLAB_TIERS_V0,
|
|
4497
5738
|
SLAB_TIERS_V1,
|
|
5739
|
+
SLAB_TIERS_V12_1,
|
|
4498
5740
|
SLAB_TIERS_V1D,
|
|
4499
5741
|
SLAB_TIERS_V1D_LEGACY,
|
|
4500
5742
|
SLAB_TIERS_V1M,
|
|
@@ -4502,6 +5744,7 @@ export {
|
|
|
4502
5744
|
SLAB_TIERS_V2,
|
|
4503
5745
|
SLAB_TIERS_V_ADL,
|
|
4504
5746
|
SLAB_TIERS_V_ADL_DISCOVERY,
|
|
5747
|
+
SLAB_TIERS_V_SETDEXPOOL,
|
|
4505
5748
|
STAKE_IX,
|
|
4506
5749
|
STAKE_POOL_SIZE,
|
|
4507
5750
|
STAKE_PROGRAM_ID,
|
|
@@ -4511,11 +5754,15 @@ export {
|
|
|
4511
5754
|
VAMM_MAGIC,
|
|
4512
5755
|
ValidationError,
|
|
4513
5756
|
WELL_KNOWN,
|
|
5757
|
+
_internal,
|
|
4514
5758
|
buildAccountMetas,
|
|
4515
5759
|
buildAdlInstruction,
|
|
4516
5760
|
buildAdlTransaction,
|
|
4517
5761
|
buildIx,
|
|
4518
5762
|
checkPhaseTransition,
|
|
5763
|
+
checkRpcHealth,
|
|
5764
|
+
classifyLighthouseError,
|
|
5765
|
+
clearStaticMarkets,
|
|
4519
5766
|
computeDexSpotPriceE6,
|
|
4520
5767
|
computeDynamicFeeBps,
|
|
4521
5768
|
computeDynamicTradingFee,
|
|
@@ -4527,6 +5774,7 @@ export {
|
|
|
4527
5774
|
computeLiqPrice,
|
|
4528
5775
|
computeMarkPnl,
|
|
4529
5776
|
computeMaxLeverage,
|
|
5777
|
+
computeMaxWithdrawable,
|
|
4530
5778
|
computePnlPercent,
|
|
4531
5779
|
computePreTradeLiqPrice,
|
|
4532
5780
|
computeRequiredMargin,
|
|
@@ -4534,14 +5782,15 @@ export {
|
|
|
4534
5782
|
computeVammQuote,
|
|
4535
5783
|
computeWarmupLeverageCap,
|
|
4536
5784
|
computeWarmupMaxPositionSize,
|
|
5785
|
+
computeWarmupProgress,
|
|
4537
5786
|
computeWarmupUnlockedCapital,
|
|
4538
5787
|
concatBytes,
|
|
5788
|
+
countLighthouseInstructions,
|
|
4539
5789
|
decodeError,
|
|
4540
5790
|
decodeStakePool,
|
|
4541
5791
|
depositAccounts,
|
|
4542
5792
|
deriveCreatorLockPda,
|
|
4543
5793
|
deriveDepositPda,
|
|
4544
|
-
deriveInsuranceLpMint,
|
|
4545
5794
|
deriveKeeperFund,
|
|
4546
5795
|
deriveLpPda,
|
|
4547
5796
|
derivePythPriceUpdateAccount,
|
|
@@ -4554,6 +5803,8 @@ export {
|
|
|
4554
5803
|
detectSlabLayout,
|
|
4555
5804
|
detectTokenProgram,
|
|
4556
5805
|
discoverMarkets,
|
|
5806
|
+
discoverMarketsViaApi,
|
|
5807
|
+
discoverMarketsViaStaticBundle,
|
|
4557
5808
|
encBool,
|
|
4558
5809
|
encI128,
|
|
4559
5810
|
encI64,
|
|
@@ -4567,26 +5818,33 @@ export {
|
|
|
4567
5818
|
encodeAdvanceEpoch,
|
|
4568
5819
|
encodeAdvanceOraclePhase,
|
|
4569
5820
|
encodeAllocateMarket,
|
|
5821
|
+
encodeAttestCrossMargin,
|
|
4570
5822
|
encodeAuditCrank,
|
|
4571
5823
|
encodeBurnPositionNft,
|
|
4572
5824
|
encodeCancelQueuedWithdrawal,
|
|
5825
|
+
encodeChallengeSettlement,
|
|
4573
5826
|
encodeClaimEpochWithdrawal,
|
|
4574
5827
|
encodeClaimQueuedWithdrawal,
|
|
4575
5828
|
encodeClearPendingSettlement,
|
|
4576
5829
|
encodeCloseAccount,
|
|
5830
|
+
encodeCloseOrphanSlab,
|
|
4577
5831
|
encodeCloseSlab,
|
|
4578
5832
|
encodeCloseStaleSlabs,
|
|
4579
|
-
|
|
5833
|
+
encodeCreateLpVault,
|
|
4580
5834
|
encodeDepositCollateral,
|
|
4581
|
-
|
|
5835
|
+
encodeDepositLpCollateral,
|
|
4582
5836
|
encodeExecuteAdl,
|
|
5837
|
+
encodeForceCloseResolved,
|
|
4583
5838
|
encodeFundMarketInsurance,
|
|
4584
5839
|
encodeInitLP,
|
|
4585
5840
|
encodeInitMarket,
|
|
5841
|
+
encodeInitMatcherCtx,
|
|
4586
5842
|
encodeInitSharedVault,
|
|
4587
5843
|
encodeInitUser,
|
|
4588
5844
|
encodeKeeperCrank,
|
|
4589
5845
|
encodeLiquidateAtOracle,
|
|
5846
|
+
encodeLpVaultCrankFees,
|
|
5847
|
+
encodeLpVaultDeposit,
|
|
4590
5848
|
encodeLpVaultWithdraw,
|
|
4591
5849
|
encodeMintPositionNft,
|
|
4592
5850
|
encodePauseMarket,
|
|
@@ -4595,9 +5853,15 @@ export {
|
|
|
4595
5853
|
encodeQueueWithdrawalSV,
|
|
4596
5854
|
encodeReclaimSlabRent,
|
|
4597
5855
|
encodeRenounceAdmin,
|
|
5856
|
+
encodeRescueOrphanVault,
|
|
5857
|
+
encodeResolveDispute,
|
|
4598
5858
|
encodeResolveMarket,
|
|
5859
|
+
encodeResolvePermissionless,
|
|
5860
|
+
encodeSetDexPool,
|
|
4599
5861
|
encodeSetInsuranceIsolation,
|
|
5862
|
+
encodeSetInsuranceWithdrawPolicy,
|
|
4600
5863
|
encodeSetMaintenanceFee,
|
|
5864
|
+
encodeSetOffsetPair,
|
|
4601
5865
|
encodeSetOiImbalanceHardBlock,
|
|
4602
5866
|
encodeSetOracleAuthority,
|
|
4603
5867
|
encodeSetOraclePriceCap,
|
|
@@ -4638,7 +5902,8 @@ export {
|
|
|
4638
5902
|
encodeUpdateRiskParams,
|
|
4639
5903
|
encodeWithdrawCollateral,
|
|
4640
5904
|
encodeWithdrawInsurance,
|
|
4641
|
-
|
|
5905
|
+
encodeWithdrawInsuranceLimited,
|
|
5906
|
+
encodeWithdrawLpCollateral,
|
|
4642
5907
|
fetchAdlRankedPositions,
|
|
4643
5908
|
fetchAdlRankings,
|
|
4644
5909
|
fetchSlab,
|
|
@@ -4650,12 +5915,18 @@ export {
|
|
|
4650
5915
|
getCurrentNetwork,
|
|
4651
5916
|
getErrorHint,
|
|
4652
5917
|
getErrorName,
|
|
5918
|
+
getMarketsByAddress,
|
|
4653
5919
|
getMatcherProgramId,
|
|
4654
5920
|
getProgramId,
|
|
4655
5921
|
getStakeProgramId,
|
|
5922
|
+
getStaticMarkets,
|
|
4656
5923
|
initPoolAccounts,
|
|
4657
5924
|
isAccountUsed,
|
|
4658
5925
|
isAdlTriggered,
|
|
5926
|
+
isAnchorErrorCode,
|
|
5927
|
+
isLighthouseError,
|
|
5928
|
+
isLighthouseFailureInLogs,
|
|
5929
|
+
isLighthouseInstruction,
|
|
4659
5930
|
isStandardToken,
|
|
4660
5931
|
isToken2022,
|
|
4661
5932
|
isValidChainlinkOracle,
|
|
@@ -4674,11 +5945,14 @@ export {
|
|
|
4674
5945
|
rankAdlPositions,
|
|
4675
5946
|
readLastThrUpdateSlot,
|
|
4676
5947
|
readNonce,
|
|
5948
|
+
registerStaticMarkets,
|
|
4677
5949
|
resolvePrice,
|
|
4678
5950
|
safeEnv,
|
|
4679
5951
|
simulateOrSend,
|
|
4680
5952
|
slabDataSize,
|
|
4681
5953
|
slabDataSizeV1,
|
|
5954
|
+
stripLighthouseFromTransaction,
|
|
5955
|
+
stripLighthouseInstructions,
|
|
4682
5956
|
validateAmount,
|
|
4683
5957
|
validateBps,
|
|
4684
5958
|
validateI128,
|
|
@@ -4689,6 +5963,7 @@ export {
|
|
|
4689
5963
|
validateU128,
|
|
4690
5964
|
validateU16,
|
|
4691
5965
|
validateU64,
|
|
5966
|
+
withRetry,
|
|
4692
5967
|
withdrawAccounts
|
|
4693
5968
|
};
|
|
4694
5969
|
//# sourceMappingURL=index.js.map
|