@percolatorct/sdk 1.0.0-beta.15 → 1.0.0-beta.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +754 -0
- package/dist/abi/accounts.d.ts +244 -0
- package/dist/abi/encode.d.ts +46 -0
- package/dist/abi/errors.d.ts +45 -0
- package/dist/abi/index.d.ts +4 -0
- package/dist/abi/instructions.d.ts +1102 -0
- package/dist/config/program-ids.d.ts +50 -0
- package/dist/index.d.ts +7 -3455
- package/dist/index.js +1049 -308
- package/dist/index.js.map +1 -1
- package/dist/math/index.d.ts +2 -0
- package/dist/math/trading.d.ts +222 -0
- package/dist/math/warmup.d.ts +105 -0
- package/dist/oracle/price-router.d.ts +38 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/lighthouse.d.ts +170 -0
- package/dist/runtime/tx.d.ts +31 -0
- package/dist/solana/adl.d.ts +305 -0
- package/dist/solana/ata.d.ts +18 -0
- package/dist/solana/dex-oracle.d.ts +49 -0
- package/dist/solana/discovery.d.ts +492 -0
- package/dist/solana/index.d.ts +11 -0
- package/dist/solana/oracle.d.ts +52 -0
- package/dist/solana/pda.d.ts +44 -0
- package/dist/solana/rpc-pool.d.ts +347 -0
- package/dist/solana/slab.d.ts +421 -0
- package/dist/solana/stake.d.ts +216 -0
- package/dist/solana/static-markets.d.ts +86 -0
- package/dist/solana/token-program.d.ts +19 -0
- package/dist/validation.d.ts +70 -0
- package/package.json +11 -5
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coin-margined perpetual trade math utilities.
|
|
3
|
+
*
|
|
4
|
+
* On-chain PnL formula:
|
|
5
|
+
* mark_pnl = (oracle - entry) * abs_pos / oracle (longs)
|
|
6
|
+
* mark_pnl = (entry - oracle) * abs_pos / oracle (shorts)
|
|
7
|
+
*
|
|
8
|
+
* All prices are in e6 format (1 USD = 1_000_000).
|
|
9
|
+
* All token amounts are in native units (e.g. lamports).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Compute mark-to-market PnL for an open position.
|
|
13
|
+
*
|
|
14
|
+
* @param positionSize - Signed position size (positive = long, negative = short).
|
|
15
|
+
* @param entryPrice - Entry price in e6 format (1 USD = 1_000_000).
|
|
16
|
+
* @param oraclePrice - Current oracle price in e6 format.
|
|
17
|
+
* @returns PnL in native token units (positive = profit, negative = loss).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* // Long 10 SOL at $100, oracle now $110 → profit
|
|
22
|
+
* const pnl = computeMarkPnl(10_000_000n, 100_000_000n, 110_000_000n);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function computeMarkPnl(positionSize: bigint, entryPrice: bigint, oraclePrice: bigint): bigint;
|
|
26
|
+
/**
|
|
27
|
+
* Compute liquidation price given entry, capital, position and maintenance margin.
|
|
28
|
+
* Uses pure BigInt arithmetic for precision (no Number() truncation).
|
|
29
|
+
*
|
|
30
|
+
* @param entryPrice - Entry price in e6 format.
|
|
31
|
+
* @param capital - Account capital in native token units.
|
|
32
|
+
* @param positionSize - Signed position size (positive = long, negative = short).
|
|
33
|
+
* @param maintenanceMarginBps - Maintenance margin requirement in basis points (e.g. 500n = 5%).
|
|
34
|
+
* @returns Liquidation price in e6 format. Returns 0n for longs that can't be liquidated,
|
|
35
|
+
* or max u64 for shorts with ≥100% maintenance margin.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* // Long 1 SOL at $100, $10 capital, 5% maintenance margin
|
|
40
|
+
* const liqPrice = computeLiqPrice(100_000_000n, 10_000_000n, 1_000_000n, 500n);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function computeLiqPrice(entryPrice: bigint, capital: bigint, positionSize: bigint, maintenanceMarginBps: bigint): bigint;
|
|
44
|
+
/**
|
|
45
|
+
* Compute estimated liquidation price BEFORE opening a trade.
|
|
46
|
+
* Accounts for trading fees reducing effective capital.
|
|
47
|
+
*
|
|
48
|
+
* @param oracleE6 - Current oracle price in e6 format (used as entry estimate).
|
|
49
|
+
* @param margin - Deposit margin in native token units.
|
|
50
|
+
* @param posSize - Intended position size (absolute value used internally).
|
|
51
|
+
* @param maintBps - Maintenance margin in basis points.
|
|
52
|
+
* @param feeBps - Trading fee in basis points.
|
|
53
|
+
* @param direction - Trade direction: `"long"` or `"short"`.
|
|
54
|
+
* @returns Estimated liquidation price in e6 format.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const liq = computePreTradeLiqPrice(
|
|
59
|
+
* 100_000_000n, 10_000_000n, 1_000_000n, 500n, 30n, "long"
|
|
60
|
+
* );
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function computePreTradeLiqPrice(oracleE6: bigint, margin: bigint, posSize: bigint, maintBps: bigint, feeBps: bigint, direction: "long" | "short"): bigint;
|
|
64
|
+
/**
|
|
65
|
+
* Compute trading fee from notional value and fee rate in bps.
|
|
66
|
+
*
|
|
67
|
+
* @param notional - Trade notional value in native token units.
|
|
68
|
+
* @param tradingFeeBps - Fee rate in basis points (e.g. 30n = 0.30%).
|
|
69
|
+
* @returns Fee amount in native token units.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* const fee = computeTradingFee(1_000_000_000n, 30n); // 0.30% of 1 SOL
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function computeTradingFee(notional: bigint, tradingFeeBps: bigint): bigint;
|
|
77
|
+
/**
|
|
78
|
+
* Dynamic fee tier configuration.
|
|
79
|
+
*/
|
|
80
|
+
export interface FeeTierConfig {
|
|
81
|
+
/** Base trading fee (Tier 1) in bps */
|
|
82
|
+
baseBps: bigint;
|
|
83
|
+
/** Tier 2 fee in bps (0 = disabled) */
|
|
84
|
+
tier2Bps: bigint;
|
|
85
|
+
/** Tier 3 fee in bps (0 = disabled) */
|
|
86
|
+
tier3Bps: bigint;
|
|
87
|
+
/** Notional threshold to enter Tier 2 (0 = tiered fees disabled) */
|
|
88
|
+
tier2Threshold: bigint;
|
|
89
|
+
/** Notional threshold to enter Tier 3 */
|
|
90
|
+
tier3Threshold: bigint;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Compute the effective fee rate in bps using the tiered fee schedule.
|
|
94
|
+
*
|
|
95
|
+
* Mirrors on-chain `compute_dynamic_fee_bps` logic:
|
|
96
|
+
* - notional < tier2Threshold → baseBps (Tier 1)
|
|
97
|
+
* - notional < tier3Threshold → tier2Bps (Tier 2)
|
|
98
|
+
* - notional >= tier3Threshold → tier3Bps (Tier 3)
|
|
99
|
+
*
|
|
100
|
+
* If tier2Threshold == 0, tiered fees are disabled (flat baseBps).
|
|
101
|
+
*/
|
|
102
|
+
export declare function computeDynamicFeeBps(notional: bigint, config: FeeTierConfig): bigint;
|
|
103
|
+
/**
|
|
104
|
+
* Compute the dynamic trading fee for a given notional and tier config.
|
|
105
|
+
*
|
|
106
|
+
* Uses ceiling division to match on-chain behavior (prevents fee evasion
|
|
107
|
+
* via micro-trades).
|
|
108
|
+
*/
|
|
109
|
+
export declare function computeDynamicTradingFee(notional: bigint, config: FeeTierConfig): bigint;
|
|
110
|
+
/**
|
|
111
|
+
* Fee split configuration.
|
|
112
|
+
*/
|
|
113
|
+
export interface FeeSplitConfig {
|
|
114
|
+
/** LP vault share in bps (0–10_000) */
|
|
115
|
+
lpBps: bigint;
|
|
116
|
+
/** Protocol treasury share in bps */
|
|
117
|
+
protocolBps: bigint;
|
|
118
|
+
/** Market creator share in bps */
|
|
119
|
+
creatorBps: bigint;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Compute fee split for a total fee amount.
|
|
123
|
+
*
|
|
124
|
+
* Returns [lpShare, protocolShare, creatorShare].
|
|
125
|
+
* If all split params are 0, 100% goes to LP (legacy behavior).
|
|
126
|
+
* Creator gets the rounding remainder to ensure total is preserved.
|
|
127
|
+
*/
|
|
128
|
+
export declare function computeFeeSplit(totalFee: bigint, config: FeeSplitConfig): [bigint, bigint, bigint];
|
|
129
|
+
/**
|
|
130
|
+
* Compute PnL as a percentage of capital.
|
|
131
|
+
*
|
|
132
|
+
* Uses BigInt scaling to avoid precision loss from Number(bigint) conversion.
|
|
133
|
+
* Number(bigint) silently truncates values above 2^53, which can produce
|
|
134
|
+
* incorrect percentages for large positions (e.g., tokens with 9 decimals
|
|
135
|
+
* where capital > ~9M tokens in native units exceeds MAX_SAFE_INTEGER).
|
|
136
|
+
*/
|
|
137
|
+
export declare function computePnlPercent(pnlTokens: bigint, capital: bigint): number;
|
|
138
|
+
/**
|
|
139
|
+
* Estimate entry price including fee impact (slippage approximation).
|
|
140
|
+
*
|
|
141
|
+
* @param oracleE6 - Current oracle price in e6 format.
|
|
142
|
+
* @param tradingFeeBps - Trading fee in basis points.
|
|
143
|
+
* @param direction - Trade direction: `"long"` or `"short"`.
|
|
144
|
+
* @returns Estimated entry price in e6 format (higher for longs, lower for shorts).
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const entry = computeEstimatedEntryPrice(100_000_000n, 30n, "long");
|
|
149
|
+
* // → 100_030_000n (oracle + 0.30% fee impact)
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export declare function computeEstimatedEntryPrice(oracleE6: bigint, tradingFeeBps: bigint, direction: "long" | "short"): bigint;
|
|
153
|
+
/**
|
|
154
|
+
* Convert per-slot funding rate (bps) to annualized percentage.
|
|
155
|
+
*
|
|
156
|
+
* @param fundingRateBpsPerSlot - Funding rate per slot in basis points (i64 from engine state).
|
|
157
|
+
* @returns Annualized funding rate as a percentage (e.g. 12.5 = 12.5% APR).
|
|
158
|
+
* @throws Error if the value exceeds Number.MAX_SAFE_INTEGER.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* const apr = computeFundingRateAnnualized(1n); // ~78.84% APR
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export declare function computeFundingRateAnnualized(fundingRateBpsPerSlot: bigint): number;
|
|
166
|
+
/**
|
|
167
|
+
* Compute margin required for a given notional and initial margin bps.
|
|
168
|
+
*
|
|
169
|
+
* @param notional - Trade notional value in native token units.
|
|
170
|
+
* @param initialMarginBps - Initial margin requirement in basis points (e.g. 1000n = 10%).
|
|
171
|
+
* @returns Required margin in native token units.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* const margin = computeRequiredMargin(10_000_000_000n, 1000n); // 10% of notional
|
|
176
|
+
* // → 1_000_000_000n
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export declare function computeRequiredMargin(notional: bigint, initialMarginBps: bigint): bigint;
|
|
180
|
+
/**
|
|
181
|
+
* Compute maximum leverage from initial margin bps.
|
|
182
|
+
*
|
|
183
|
+
* Formula: leverage = 10000 / initialMarginBps
|
|
184
|
+
* Uses scaled arithmetic to preserve precision for fractional leverage values.
|
|
185
|
+
*
|
|
186
|
+
* @param initialMarginBps - Initial margin requirement in basis points (e.g. 500n = 5% → 20x).
|
|
187
|
+
* @returns Maximum leverage as a number (e.g. 20 for 500 bps, 3.003 for 3333 bps).
|
|
188
|
+
* @throws Error if initialMarginBps is zero (infinite leverage is undefined).
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* const maxLev = computeMaxLeverage(500n); // → 20
|
|
193
|
+
* const maxLev2 = computeMaxLeverage(1000n); // → 10
|
|
194
|
+
* const maxLev3 = computeMaxLeverage(3333n); // → 3.003 (not truncated to 3)
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
export declare function computeMaxLeverage(initialMarginBps: bigint): number;
|
|
198
|
+
/**
|
|
199
|
+
* Compute the maximum amount that can be withdrawn from a position.
|
|
200
|
+
*
|
|
201
|
+
* The withdrawable amount is the capital plus any matured (unreserved) PnL.
|
|
202
|
+
* Reserved PnL is still locked and cannot be withdrawn until the warmup period elapses.
|
|
203
|
+
*
|
|
204
|
+
* Formula: max_withdrawable = capital + max(0, pnl - reserved_pnl)
|
|
205
|
+
*
|
|
206
|
+
* @param capital - Capital allocated to the position (in native token units)
|
|
207
|
+
* @param pnl - Mark-to-market PnL (in native token units, can be negative)
|
|
208
|
+
* @param reservedPnl - PnL that is still locked during warmup (always non-negative)
|
|
209
|
+
* @returns The maximum amount in native units that can be withdrawn without closing the position
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* // Position: 10 SOL capital, +2 SOL mark PnL, 0.5 SOL reserved
|
|
214
|
+
* const max = computeMaxWithdrawable(
|
|
215
|
+
* 10_000_000_000n, // 10 SOL in lamports
|
|
216
|
+
* 2_000_000_000n, // +2 SOL in lamports
|
|
217
|
+
* 500_000_000n // 0.5 SOL reserved in lamports
|
|
218
|
+
* );
|
|
219
|
+
* // Returns: 11_500_000_000n (10 + (2 - 0.5) = 11.5 SOL in lamports)
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
export declare function computeMaxWithdrawable(capital: bigint, pnl: bigint, reservedPnl: bigint): bigint;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warmup leverage cap utilities.
|
|
3
|
+
*
|
|
4
|
+
* During the market warmup period, capital is released linearly over
|
|
5
|
+
* `warmupPeriodSlots` slots, which constrains the effective leverage
|
|
6
|
+
* and maximum position size available to traders.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Compute unlocked capital during the warmup period.
|
|
10
|
+
*
|
|
11
|
+
* Capital is released linearly over `warmupPeriodSlots` slots starting from
|
|
12
|
+
* `warmupStartedAtSlot`. Before warmup starts (startSlot === 0) or if the
|
|
13
|
+
* warmup period is 0, all capital is considered unlocked.
|
|
14
|
+
*
|
|
15
|
+
* @param totalCapital - Total deposited capital (native units).
|
|
16
|
+
* @param currentSlot - The current on-chain slot.
|
|
17
|
+
* @param warmupStartSlot - Slot at which warmup started (0 = not started).
|
|
18
|
+
* @param warmupPeriodSlots - Total slots in the warmup period.
|
|
19
|
+
* @returns The amount of capital currently unlocked.
|
|
20
|
+
*/
|
|
21
|
+
export declare function computeWarmupUnlockedCapital(totalCapital: bigint, currentSlot: bigint, warmupStartSlot: bigint, warmupPeriodSlots: bigint): bigint;
|
|
22
|
+
/**
|
|
23
|
+
* Compute the effective maximum leverage during the warmup period.
|
|
24
|
+
*
|
|
25
|
+
* During warmup, only unlocked capital can be used as margin. The effective
|
|
26
|
+
* leverage relative to *total* capital is therefore capped at:
|
|
27
|
+
*
|
|
28
|
+
* effectiveMaxLeverage = maxLeverage × (unlockedCapital / totalCapital)
|
|
29
|
+
*
|
|
30
|
+
* This returns a floored integer value (leverage is always a whole number
|
|
31
|
+
* in the UI), with a minimum of 1x if any capital is unlocked.
|
|
32
|
+
*
|
|
33
|
+
* @param initialMarginBps - Initial margin requirement in basis points.
|
|
34
|
+
* @param totalCapital - Total deposited capital (native units).
|
|
35
|
+
* @param currentSlot - The current on-chain slot.
|
|
36
|
+
* @param warmupStartSlot - Slot at which warmup started (0 = not started).
|
|
37
|
+
* @param warmupPeriodSlots - Total slots in the warmup period.
|
|
38
|
+
* @returns The effective maximum leverage (integer, ≥ 1).
|
|
39
|
+
*/
|
|
40
|
+
export declare function computeWarmupLeverageCap(initialMarginBps: bigint, totalCapital: bigint, currentSlot: bigint, warmupStartSlot: bigint, warmupPeriodSlots: bigint): number;
|
|
41
|
+
/**
|
|
42
|
+
* Compute the maximum position size allowed during warmup.
|
|
43
|
+
*
|
|
44
|
+
* This is the unlocked capital multiplied by the base max leverage.
|
|
45
|
+
* Unlike `computeWarmupLeverageCap` (which gives effective leverage
|
|
46
|
+
* relative to total capital), this gives the absolute notional cap.
|
|
47
|
+
*
|
|
48
|
+
* @param initialMarginBps - Initial margin requirement in basis points.
|
|
49
|
+
* @param totalCapital - Total deposited capital (native units).
|
|
50
|
+
* @param currentSlot - The current on-chain slot.
|
|
51
|
+
* @param warmupStartSlot - Slot at which warmup started (0 = not started).
|
|
52
|
+
* @param warmupPeriodSlots - Total slots in the warmup period.
|
|
53
|
+
* @returns Maximum position size in native units.
|
|
54
|
+
*/
|
|
55
|
+
export declare function computeWarmupMaxPositionSize(initialMarginBps: bigint, totalCapital: bigint, currentSlot: bigint, warmupStartSlot: bigint, warmupPeriodSlots: bigint): bigint;
|
|
56
|
+
/**
|
|
57
|
+
* Warmup progress information for a position.
|
|
58
|
+
*/
|
|
59
|
+
export interface WarmupProgress {
|
|
60
|
+
/** PnL available for withdrawal right now (not locked by warmup). */
|
|
61
|
+
maturedPnl: bigint;
|
|
62
|
+
/** PnL still locked until warmup completes. */
|
|
63
|
+
reservedPnl: bigint;
|
|
64
|
+
/** Progress toward full warmup as a basis point (0–10,000). */
|
|
65
|
+
progressBps: bigint;
|
|
66
|
+
/** Slots remaining until full warmup (0 if fully matured). */
|
|
67
|
+
slotsRemaining: bigint;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Compute PnL warmup progress for a position.
|
|
71
|
+
*
|
|
72
|
+
* During the warmup period, a position's unrealized PnL is linearly released.
|
|
73
|
+
* The portion available for withdrawal grows over time. This utility shows:
|
|
74
|
+
* - How much PnL is currently available (matured)
|
|
75
|
+
* - How much is still locked (reserved)
|
|
76
|
+
* - Progress toward full maturation (as %)
|
|
77
|
+
* - Slots remaining
|
|
78
|
+
*
|
|
79
|
+
* Users can display a progress bar or "unlocks in X slots" message to give
|
|
80
|
+
* transparency into when their PnL becomes withdrawable.
|
|
81
|
+
*
|
|
82
|
+
* @param currentSlot - Current on-chain slot (from engine state).
|
|
83
|
+
* @param warmupStartedAtSlot - Slot when this position's warmup started.
|
|
84
|
+
* @param warmupPeriodSlots - Total warmup duration in slots (from market config).
|
|
85
|
+
* @param pnl - Total realized + unrealized PnL (from account).
|
|
86
|
+
* @param reservedPnl - PnL locked during warmup (from account).
|
|
87
|
+
* @returns WarmupProgress with matured/reserved PnL, progress %, and slots remaining.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* const progress = computeWarmupProgress(
|
|
92
|
+
* 10000n, // current slot
|
|
93
|
+
* 9000n, // warmup started at slot 9000
|
|
94
|
+
* 2000n, // warmup period = 2000 slots
|
|
95
|
+
* 1000000000n, // pnl = 1 SOL
|
|
96
|
+
* 600000000n // reserved = 0.6 SOL (60% still locked)
|
|
97
|
+
* );
|
|
98
|
+
* // Returns:
|
|
99
|
+
* // maturedPnl: 400000000n (0.4 SOL available)
|
|
100
|
+
* // reservedPnl: 600000000n (0.6 SOL locked)
|
|
101
|
+
* // progressBps: 5000n (50% complete)
|
|
102
|
+
* // slotsRemaining: 1000n (1000 slots until fully mature)
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function computeWarmupProgress(currentSlot: bigint, warmupStartedAtSlot: bigint, warmupPeriodSlots: bigint, pnl: bigint, reservedPnl: bigint): WarmupProgress;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Price Router — automatic oracle selection for any token.
|
|
3
|
+
*
|
|
4
|
+
* Given a token mint, discovers all available price sources (DexScreener, Pyth, Jupiter),
|
|
5
|
+
* ranks them by liquidity/reliability, and returns the best oracle config.
|
|
6
|
+
*/
|
|
7
|
+
export type PriceSourceType = "pyth" | "dex" | "jupiter";
|
|
8
|
+
export interface PriceSource {
|
|
9
|
+
type: PriceSourceType;
|
|
10
|
+
/** Pool address (dex), Pyth feed ID (pyth), or mint (jupiter) */
|
|
11
|
+
address: string;
|
|
12
|
+
/** DEX id for dex sources */
|
|
13
|
+
dexId?: string;
|
|
14
|
+
/** Pair label e.g. "SOL / USDC" */
|
|
15
|
+
pairLabel?: string;
|
|
16
|
+
/** USD liquidity depth — higher is better */
|
|
17
|
+
liquidity: number;
|
|
18
|
+
/** Latest spot price in USD */
|
|
19
|
+
price: number;
|
|
20
|
+
/** Confidence score 0-100 (composite of liquidity, staleness, reliability) */
|
|
21
|
+
confidence: number;
|
|
22
|
+
}
|
|
23
|
+
export interface PriceRouterResult {
|
|
24
|
+
mint: string;
|
|
25
|
+
bestSource: PriceSource | null;
|
|
26
|
+
allSources: PriceSource[];
|
|
27
|
+
/** ISO timestamp of resolution */
|
|
28
|
+
resolvedAt: string;
|
|
29
|
+
}
|
|
30
|
+
/** Options for {@link resolvePrice}. */
|
|
31
|
+
export interface ResolvePriceOptions {
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
}
|
|
34
|
+
export declare const PYTH_SOLANA_FEEDS: Record<string, {
|
|
35
|
+
symbol: string;
|
|
36
|
+
mint: string;
|
|
37
|
+
}>;
|
|
38
|
+
export declare function resolvePrice(mint: string, signal?: AbortSignal, options?: ResolvePriceOptions): Promise<PriceRouterResult>;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module lighthouse
|
|
3
|
+
* Lighthouse v2 (Blowfish / Phantom wallet middleware) detection and mitigation.
|
|
4
|
+
*
|
|
5
|
+
* Lighthouse (program L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95) is an Anchor-based
|
|
6
|
+
* wallet guard injected by Phantom and other Solana wallets via the Blowfish transaction
|
|
7
|
+
* scanning service. It adds assertion instructions to transactions that verify account
|
|
8
|
+
* state expectations (e.g., "this account should be empty" or "this account should have
|
|
9
|
+
* X lamports").
|
|
10
|
+
*
|
|
11
|
+
* **Problem:** Lighthouse doesn't understand Percolator's slab accounts. When a slab
|
|
12
|
+
* (e.g., ESa89R5 with 323,312 bytes) is passed as a TradeCpi account, Lighthouse injects
|
|
13
|
+
* an assertion like `StateInvalidAddress` that expects `data_len == 0` (uninitialised).
|
|
14
|
+
* The slab IS initialised, so the assertion fails with error 0x1900 (Anchor ConstraintAddress
|
|
15
|
+
* = 6400 decimal). This causes the transaction to revert even though the Percolator program
|
|
16
|
+
* logic is correct.
|
|
17
|
+
*
|
|
18
|
+
* **Solution:** The SDK provides utilities to:
|
|
19
|
+
* 1. Detect Lighthouse instructions in a transaction
|
|
20
|
+
* 2. Strip them before sending
|
|
21
|
+
* 3. Classify 0x1900 errors as Lighthouse (not Percolator) errors
|
|
22
|
+
* 4. Provide clear, actionable error messages for end users
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { isLighthouseError, stripLighthouseInstructions, LIGHTHOUSE_PROGRAM_ID } from "@percolator/sdk";
|
|
27
|
+
*
|
|
28
|
+
* // Before sending: strip injected Lighthouse IXs
|
|
29
|
+
* const cleanIxs = stripLighthouseInstructions(instructions);
|
|
30
|
+
*
|
|
31
|
+
* // After error: classify and give user-friendly message
|
|
32
|
+
* if (isLighthouseError(error)) {
|
|
33
|
+
* console.warn("Wallet middleware blocked the transaction");
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
import { PublicKey, TransactionInstruction, Transaction } from "@solana/web3.js";
|
|
38
|
+
/**
|
|
39
|
+
* Lighthouse v2 program ID (Blowfish/Phantom wallet guard).
|
|
40
|
+
*
|
|
41
|
+
* This is an immutable Anchor program deployed at slot 294,179,293.
|
|
42
|
+
* Wallets like Phantom inject instructions from this program into user
|
|
43
|
+
* transactions to enforce Blowfish security assertions.
|
|
44
|
+
*/
|
|
45
|
+
export declare const LIGHTHOUSE_PROGRAM_ID: PublicKey;
|
|
46
|
+
/** Base58 string form for fast comparison without PublicKey instantiation. */
|
|
47
|
+
export declare const LIGHTHOUSE_PROGRAM_ID_STR = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95";
|
|
48
|
+
/**
|
|
49
|
+
* Anchor error code for ConstraintAddress (0x1900 = 6400 decimal).
|
|
50
|
+
* This is NOT a Percolator error — it comes from Lighthouse's Anchor framework
|
|
51
|
+
* when an account constraint check fails.
|
|
52
|
+
*/
|
|
53
|
+
export declare const LIGHTHOUSE_CONSTRAINT_ADDRESS = 6400;
|
|
54
|
+
/**
|
|
55
|
+
* Known Lighthouse/Anchor error codes that may appear in transaction logs.
|
|
56
|
+
* All are in the Anchor error range (0x1770–0x1900+).
|
|
57
|
+
*/
|
|
58
|
+
export declare const LIGHTHOUSE_ERROR_CODES: Set<6000 | 6032 | 6036 | 6038 | 6400 | 6001 | 6002 | 6003 | 6016 | 6033 | 6034 | 6035 | 6037 | 6039 | 6040 | 6041 | 6042 | 6043>;
|
|
59
|
+
/**
|
|
60
|
+
* Check if a TransactionInstruction is from the Lighthouse program.
|
|
61
|
+
*
|
|
62
|
+
* @param ix - A Solana transaction instruction.
|
|
63
|
+
* @returns `true` if the instruction's programId is Lighthouse.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const hasLighthouse = instructions.some(isLighthouseInstruction);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function isLighthouseInstruction(ix: TransactionInstruction): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Check if an error message or error object indicates a Lighthouse assertion failure.
|
|
73
|
+
*
|
|
74
|
+
* Detects:
|
|
75
|
+
* - `custom program error: 0x1900` (Anchor ConstraintAddress from Lighthouse)
|
|
76
|
+
* - References to the Lighthouse program ID in error text
|
|
77
|
+
* - `"Custom": 6400` in JSON-encoded InstructionError
|
|
78
|
+
* - Any Anchor error code in the LIGHTHOUSE_ERROR_CODES range when the
|
|
79
|
+
* failing program is Lighthouse (identified by program ID in logs)
|
|
80
|
+
*
|
|
81
|
+
* @param error - An Error object, error message string, or transaction logs array.
|
|
82
|
+
* @returns `true` if the error appears to originate from Lighthouse, not Percolator.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* try {
|
|
87
|
+
* await sendTransaction(tx);
|
|
88
|
+
* } catch (e) {
|
|
89
|
+
* if (isLighthouseError(e)) {
|
|
90
|
+
* // Retry with skipPreflight or notify user about wallet middleware
|
|
91
|
+
* }
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare function isLighthouseError(error: unknown): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Check if transaction logs contain evidence of a Lighthouse failure.
|
|
98
|
+
*
|
|
99
|
+
* More precise than `isLighthouseError` on a string — examines the program
|
|
100
|
+
* invocation chain to confirm the error originates from Lighthouse, not from
|
|
101
|
+
* a Percolator instruction that happens to return a similar code.
|
|
102
|
+
*
|
|
103
|
+
* @param logs - Array of transaction log lines from `getTransaction()`.
|
|
104
|
+
* @returns `true` if logs show a Lighthouse program failure.
|
|
105
|
+
*/
|
|
106
|
+
export declare function isLighthouseFailureInLogs(logs: string[]): boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Remove all Lighthouse assertion instructions from an instruction array.
|
|
109
|
+
*
|
|
110
|
+
* Call this before building a Transaction to prevent Lighthouse assertion
|
|
111
|
+
* failures. Safe to call even if no Lighthouse instructions are present.
|
|
112
|
+
*
|
|
113
|
+
* @param instructions - Array of transaction instructions.
|
|
114
|
+
* @returns Filtered array with Lighthouse instructions removed.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* import { stripLighthouseInstructions } from "@percolator/sdk";
|
|
119
|
+
*
|
|
120
|
+
* const instructions = [crankIx, tradeIx]; // May have Lighthouse IXs mixed in
|
|
121
|
+
* const clean = stripLighthouseInstructions(instructions);
|
|
122
|
+
* const tx = new Transaction().add(...clean);
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export declare function stripLighthouseInstructions(instructions: TransactionInstruction[], percolatorProgramId?: PublicKey): TransactionInstruction[];
|
|
126
|
+
/**
|
|
127
|
+
* Strip Lighthouse instructions from an already-built Transaction.
|
|
128
|
+
*
|
|
129
|
+
* Creates a new Transaction with the same recentBlockhash and feePayer
|
|
130
|
+
* but without any Lighthouse instructions. The returned transaction is
|
|
131
|
+
* unsigned and must be re-signed.
|
|
132
|
+
*
|
|
133
|
+
* @param transaction - A Transaction (signed or unsigned).
|
|
134
|
+
* @returns A new Transaction without Lighthouse instructions, or the same
|
|
135
|
+
* transaction if no Lighthouse instructions were found.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* const signed = await wallet.signTransaction(tx);
|
|
140
|
+
* if (hasLighthouseInstructions(signed)) {
|
|
141
|
+
* const clean = stripLighthouseFromTransaction(signed);
|
|
142
|
+
* const reSigned = await wallet.signTransaction(clean);
|
|
143
|
+
* await connection.sendRawTransaction(reSigned.serialize());
|
|
144
|
+
* }
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export declare function stripLighthouseFromTransaction(transaction: Transaction, percolatorProgramId?: PublicKey): Transaction;
|
|
148
|
+
/**
|
|
149
|
+
* Count Lighthouse instructions in an instruction array or transaction.
|
|
150
|
+
*
|
|
151
|
+
* @param ixsOrTx - Array of instructions or a Transaction.
|
|
152
|
+
* @returns Number of Lighthouse instructions found.
|
|
153
|
+
*/
|
|
154
|
+
export declare function countLighthouseInstructions(ixsOrTx: TransactionInstruction[] | Transaction): number;
|
|
155
|
+
/**
|
|
156
|
+
* User-friendly error message for Lighthouse assertion failures.
|
|
157
|
+
*
|
|
158
|
+
* Suitable for display in UI toast/modal when `isLighthouseError()` returns true.
|
|
159
|
+
*/
|
|
160
|
+
export declare const LIGHTHOUSE_USER_MESSAGE: string;
|
|
161
|
+
/**
|
|
162
|
+
* Classify an error and return an appropriate user-facing message.
|
|
163
|
+
*
|
|
164
|
+
* If the error is from Lighthouse, returns the Lighthouse-specific message.
|
|
165
|
+
* Otherwise returns `null` (callers should use their own error display).
|
|
166
|
+
*
|
|
167
|
+
* @param error - An Error, string, or logs array.
|
|
168
|
+
* @returns User-facing message string, or `null` if not a Lighthouse error.
|
|
169
|
+
*/
|
|
170
|
+
export declare function classifyLighthouseError(error: unknown): string | null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Connection, PublicKey, TransactionInstruction, Keypair, Commitment, AccountMeta } from "@solana/web3.js";
|
|
2
|
+
export interface BuildIxParams {
|
|
3
|
+
programId: PublicKey;
|
|
4
|
+
keys: AccountMeta[];
|
|
5
|
+
data: Uint8Array | Buffer;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Build a transaction instruction.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildIx(params: BuildIxParams): TransactionInstruction;
|
|
11
|
+
export interface TxResult {
|
|
12
|
+
signature: string;
|
|
13
|
+
slot: number;
|
|
14
|
+
err: string | null;
|
|
15
|
+
hint?: string;
|
|
16
|
+
logs: string[];
|
|
17
|
+
unitsConsumed?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface SimulateOrSendParams {
|
|
20
|
+
connection: Connection;
|
|
21
|
+
ix: TransactionInstruction;
|
|
22
|
+
signers: Keypair[];
|
|
23
|
+
simulate: boolean;
|
|
24
|
+
commitment?: Commitment;
|
|
25
|
+
computeUnitLimit?: number;
|
|
26
|
+
}
|
|
27
|
+
export declare function simulateOrSend(params: SimulateOrSendParams): Promise<TxResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Format transaction result for output.
|
|
30
|
+
*/
|
|
31
|
+
export declare function formatResult(result: TxResult, jsonMode: boolean): string;
|