sol-trade-sdk 0.1.0
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 +390 -0
- package/dist/chunk-MMQAMIKR.mjs +3735 -0
- package/dist/chunk-NEZDFAYA.mjs +7744 -0
- package/dist/clients-VITWK7B6.mjs +1370 -0
- package/dist/index-1BK_FXsW.d.mts +2327 -0
- package/dist/index-1BK_FXsW.d.ts +2327 -0
- package/dist/index.d.mts +2659 -0
- package/dist/index.d.ts +2659 -0
- package/dist/index.js +13265 -0
- package/dist/index.mjs +562 -0
- package/dist/perf/index.d.mts +2 -0
- package/dist/perf/index.d.ts +2 -0
- package/dist/perf/index.js +3742 -0
- package/dist/perf/index.mjs +214 -0
- package/package.json +101 -0
- package/src/__tests__/complete_sdk.test.ts +354 -0
- package/src/__tests__/hotpath.test.ts +486 -0
- package/src/__tests__/nonce.test.ts +45 -0
- package/src/__tests__/sdk.test.ts +425 -0
- package/src/address-lookup/index.ts +197 -0
- package/src/cache/cache.ts +308 -0
- package/src/calc/index.ts +1058 -0
- package/src/calc/pumpfun.ts +124 -0
- package/src/common/bonding_curve.ts +272 -0
- package/src/common/compute-budget.ts +148 -0
- package/src/common/confirm-any-signature.ts +184 -0
- package/src/common/fast-timing.ts +481 -0
- package/src/common/fast_fn.ts +150 -0
- package/src/common/gas-fee-strategy.ts +253 -0
- package/src/common/map-pool.ts +23 -0
- package/src/common/nonce.ts +40 -0
- package/src/common/sdk-log.ts +460 -0
- package/src/common/seed.ts +381 -0
- package/src/common/spl-token.ts +578 -0
- package/src/common/subscription-handle.ts +644 -0
- package/src/common/trading-utils.ts +239 -0
- package/src/common/wsol-manager.ts +325 -0
- package/src/compute/compute_budget_manager.ts +187 -0
- package/src/compute/index.ts +21 -0
- package/src/constants/index.ts +96 -0
- package/src/execution/execution.ts +532 -0
- package/src/execution/index.ts +42 -0
- package/src/hotpath/executor.ts +464 -0
- package/src/hotpath/index.ts +64 -0
- package/src/hotpath/state.ts +435 -0
- package/src/index.ts +2117 -0
- package/src/instruction/bonk_builder.ts +730 -0
- package/src/instruction/index.ts +24 -0
- package/src/instruction/meteora_damm_v2_builder.ts +509 -0
- package/src/instruction/pumpfun_builder.ts +1183 -0
- package/src/instruction/pumpswap.ts +1123 -0
- package/src/instruction/raydium_amm_v4_builder.ts +692 -0
- package/src/instruction/raydium_cpmm_builder.ts +795 -0
- package/src/middleware/traits.ts +407 -0
- package/src/params/index.ts +483 -0
- package/src/perf/compiler-optimization.ts +529 -0
- package/src/perf/hardware.ts +631 -0
- package/src/perf/index.ts +9 -0
- package/src/perf/kernel-bypass.ts +656 -0
- package/src/perf/protocol.ts +682 -0
- package/src/perf/realtime.ts +592 -0
- package/src/perf/simd.ts +668 -0
- package/src/perf/syscall-bypass.ts +331 -0
- package/src/perf/ultra-low-latency.ts +505 -0
- package/src/perf/zero-copy.ts +589 -0
- package/src/pool/pool.ts +294 -0
- package/src/rpc/client.ts +345 -0
- package/src/sdk-errors.ts +13 -0
- package/src/security/index.ts +26 -0
- package/src/security/secure-key.ts +303 -0
- package/src/security/validators.ts +281 -0
- package/src/seed/pda.ts +262 -0
- package/src/serialization/index.ts +28 -0
- package/src/serialization/serialization.ts +288 -0
- package/src/swqos/clients.ts +1754 -0
- package/src/swqos/index.ts +50 -0
- package/src/swqos/providers.ts +1707 -0
- package/src/trading/core/async-executor.ts +702 -0
- package/src/trading/core/confirmation-monitor.ts +711 -0
- package/src/trading/core/index.ts +82 -0
- package/src/trading/core/retry-handler.ts +683 -0
- package/src/trading/core/transaction-pool.ts +780 -0
- package/src/trading/executor.ts +385 -0
- package/src/trading/factory.ts +282 -0
- package/src/trading/index.ts +30 -0
- package/src/types.ts +8 -0
- package/src/utils/index.ts +155 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PumpFun bonding curve calculations.
|
|
3
|
+
* Based on sol-trade-sdk Rust implementation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Constants from Rust
|
|
7
|
+
export const FEE_BASIS_POINTS = 100; // 1%
|
|
8
|
+
export const CREATOR_FEE = 50; // 0.5%
|
|
9
|
+
export const INITIAL_VIRTUAL_TOKEN_RESERVES = 1_073_000_000_000_000;
|
|
10
|
+
export const INITIAL_VIRTUAL_SOL_RESERVES = 30_000_000_000; // 30 SOL
|
|
11
|
+
export const INITIAL_REAL_TOKEN_RESERVES = 793_100_000_000_000;
|
|
12
|
+
export const TOKEN_TOTAL_SUPPLY = 1_000_000_000_000_000;
|
|
13
|
+
export const LAMPORTS_PER_SOL = 1_000_000_000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Compute fee for a given amount
|
|
17
|
+
*/
|
|
18
|
+
export function computeFee(amount: number, feeBasisPoints: number): number {
|
|
19
|
+
return Math.floor((amount * feeBasisPoints) / 10_000);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Calculate token amount received for given SOL amount using bonding curve formula
|
|
24
|
+
*/
|
|
25
|
+
export function getBuyTokenAmountFromSolAmount(
|
|
26
|
+
virtualTokenReserves: number,
|
|
27
|
+
virtualSolReserves: number,
|
|
28
|
+
realTokenReserves: number,
|
|
29
|
+
creator: Uint8Array,
|
|
30
|
+
amount: number,
|
|
31
|
+
): number {
|
|
32
|
+
if (amount === 0) {
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (virtualTokenReserves === 0) {
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Calculate total fee
|
|
41
|
+
const hasCreator = creator.some(b => b !== 0);
|
|
42
|
+
const totalFeeBasisPoints = FEE_BASIS_POINTS + (hasCreator ? CREATOR_FEE : 0);
|
|
43
|
+
|
|
44
|
+
// Calculate input amount after fees
|
|
45
|
+
const inputAmount = Math.floor((amount * 10_000) / (totalFeeBasisPoints + 10_000));
|
|
46
|
+
|
|
47
|
+
const denominator = virtualSolReserves + inputAmount;
|
|
48
|
+
|
|
49
|
+
let tokensReceived = Math.floor((inputAmount * virtualTokenReserves) / denominator);
|
|
50
|
+
|
|
51
|
+
// Cap at real reserves
|
|
52
|
+
tokensReceived = Math.min(tokensReceived, realTokenReserves);
|
|
53
|
+
|
|
54
|
+
// Special handling for small amounts
|
|
55
|
+
if (tokensReceived <= 100 * 1_000_000) {
|
|
56
|
+
if (amount > 0.01 * LAMPORTS_PER_SOL) {
|
|
57
|
+
tokensReceived = 25547619 * 1_000_000;
|
|
58
|
+
} else {
|
|
59
|
+
tokensReceived = 255476 * 1_000_000;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return tokensReceived;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Calculate SOL amount received for given token amount
|
|
68
|
+
*/
|
|
69
|
+
export function getSellSolAmountFromTokenAmount(
|
|
70
|
+
virtualTokenReserves: number,
|
|
71
|
+
virtualSolReserves: number,
|
|
72
|
+
creator: Uint8Array,
|
|
73
|
+
amount: number,
|
|
74
|
+
): number {
|
|
75
|
+
if (amount === 0) {
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (virtualTokenReserves === 0) {
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Calculate SOL received
|
|
84
|
+
const numerator = amount * virtualSolReserves;
|
|
85
|
+
const denominator = virtualTokenReserves + amount;
|
|
86
|
+
|
|
87
|
+
const solCost = Math.floor(numerator / denominator);
|
|
88
|
+
|
|
89
|
+
// Calculate fee
|
|
90
|
+
const hasCreator = creator.some(b => b !== 0);
|
|
91
|
+
const totalFeeBasisPoints = FEE_BASIS_POINTS + (hasCreator ? CREATOR_FEE : 0);
|
|
92
|
+
|
|
93
|
+
const fee = computeFee(solCost, totalFeeBasisPoints);
|
|
94
|
+
|
|
95
|
+
return Math.max(0, solCost - fee);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Calculate max SOL cost with slippage for buy
|
|
100
|
+
*/
|
|
101
|
+
export function calculateWithSlippageBuy(amount: number, slippageBasisPoints: number): number {
|
|
102
|
+
return amount + Math.floor((amount * slippageBasisPoints) / 10_000);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Calculate min tokens out with slippage for sell
|
|
107
|
+
*/
|
|
108
|
+
export function calculateWithSlippageSell(amount: number, slippageBasisPoints: number): number {
|
|
109
|
+
return amount - Math.floor((amount * slippageBasisPoints) / 10_000);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Convert lamports to SOL
|
|
114
|
+
*/
|
|
115
|
+
export function lamportsToSol(lamports: number): number {
|
|
116
|
+
return lamports / LAMPORTS_PER_SOL;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Convert SOL to lamports
|
|
121
|
+
*/
|
|
122
|
+
export function solToLamports(sol: number): number {
|
|
123
|
+
return Math.floor(sol * LAMPORTS_PER_SOL);
|
|
124
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bonding curve account for Pump.fun.
|
|
3
|
+
* Based on sol-trade-sdk Rust implementation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { PublicKey } from '@solana/web3.js';
|
|
7
|
+
import {
|
|
8
|
+
getBuyTokenAmountFromSolAmount,
|
|
9
|
+
getSellSolAmountFromTokenAmount,
|
|
10
|
+
INITIAL_VIRTUAL_TOKEN_RESERVES,
|
|
11
|
+
INITIAL_VIRTUAL_SOL_RESERVES,
|
|
12
|
+
INITIAL_REAL_TOKEN_RESERVES,
|
|
13
|
+
TOKEN_TOTAL_SUPPLY,
|
|
14
|
+
} from '../calc/pumpfun';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Represents the bonding curve account for token pricing
|
|
18
|
+
*/
|
|
19
|
+
export class BondingCurveAccount {
|
|
20
|
+
discriminator: number = 0;
|
|
21
|
+
account: PublicKey = PublicKey.default;
|
|
22
|
+
virtualTokenReserves: number = 0;
|
|
23
|
+
virtualSolReserves: number = 0;
|
|
24
|
+
realTokenReserves: number = 0;
|
|
25
|
+
realSolReserves: number = 0;
|
|
26
|
+
tokenTotalSupply: number = TOKEN_TOTAL_SUPPLY;
|
|
27
|
+
complete: boolean = false;
|
|
28
|
+
creator: PublicKey = PublicKey.default;
|
|
29
|
+
isMayhemMode: boolean = false;
|
|
30
|
+
isCashbackCoin: boolean = false;
|
|
31
|
+
|
|
32
|
+
constructor(fields?: Partial<BondingCurveAccount>) {
|
|
33
|
+
if (fields) {
|
|
34
|
+
Object.assign(this, fields);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create from dev trade data
|
|
40
|
+
*/
|
|
41
|
+
static fromDevTrade(
|
|
42
|
+
bondingCurve: PublicKey,
|
|
43
|
+
mint: PublicKey,
|
|
44
|
+
devTokenAmount: number,
|
|
45
|
+
devSolAmount: number,
|
|
46
|
+
creator: PublicKey,
|
|
47
|
+
isMayhemMode: boolean = false,
|
|
48
|
+
isCashbackCoin: boolean = false,
|
|
49
|
+
): BondingCurveAccount {
|
|
50
|
+
return new BondingCurveAccount({
|
|
51
|
+
discriminator: 0,
|
|
52
|
+
account: bondingCurve,
|
|
53
|
+
virtualTokenReserves: INITIAL_VIRTUAL_TOKEN_RESERVES - devTokenAmount,
|
|
54
|
+
virtualSolReserves: INITIAL_VIRTUAL_SOL_RESERVES + devSolAmount,
|
|
55
|
+
realTokenReserves: INITIAL_REAL_TOKEN_RESERVES - devTokenAmount,
|
|
56
|
+
realSolReserves: devSolAmount,
|
|
57
|
+
tokenTotalSupply: TOKEN_TOTAL_SUPPLY,
|
|
58
|
+
complete: false,
|
|
59
|
+
creator,
|
|
60
|
+
isMayhemMode,
|
|
61
|
+
isCashbackCoin,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Create from trade data
|
|
67
|
+
*/
|
|
68
|
+
static fromTrade(
|
|
69
|
+
bondingCurve: PublicKey,
|
|
70
|
+
mint: PublicKey,
|
|
71
|
+
creator: PublicKey,
|
|
72
|
+
virtualTokenReserves: number,
|
|
73
|
+
virtualSolReserves: number,
|
|
74
|
+
realTokenReserves: number,
|
|
75
|
+
realSolReserves: number,
|
|
76
|
+
isMayhemMode: boolean = false,
|
|
77
|
+
isCashbackCoin: boolean = false,
|
|
78
|
+
): BondingCurveAccount {
|
|
79
|
+
return new BondingCurveAccount({
|
|
80
|
+
discriminator: 0,
|
|
81
|
+
account: bondingCurve,
|
|
82
|
+
virtualTokenReserves,
|
|
83
|
+
virtualSolReserves,
|
|
84
|
+
realTokenReserves,
|
|
85
|
+
realSolReserves,
|
|
86
|
+
tokenTotalSupply: TOKEN_TOTAL_SUPPLY,
|
|
87
|
+
complete: false,
|
|
88
|
+
creator,
|
|
89
|
+
isMayhemMode,
|
|
90
|
+
isCashbackCoin,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Calculate tokens received for given SOL amount
|
|
96
|
+
*/
|
|
97
|
+
getBuyPrice(amount: number): number {
|
|
98
|
+
if (this.complete) {
|
|
99
|
+
throw new Error('Curve is complete');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return getBuyTokenAmountFromSolAmount(
|
|
103
|
+
this.virtualTokenReserves,
|
|
104
|
+
this.virtualSolReserves,
|
|
105
|
+
this.realTokenReserves,
|
|
106
|
+
this.creator.toBytes(),
|
|
107
|
+
amount,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Calculate SOL received for given token amount
|
|
113
|
+
*/
|
|
114
|
+
getSellPrice(amount: number): number {
|
|
115
|
+
if (this.complete) {
|
|
116
|
+
throw new Error('Curve is complete');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return getSellSolAmountFromTokenAmount(
|
|
120
|
+
this.virtualTokenReserves,
|
|
121
|
+
this.virtualSolReserves,
|
|
122
|
+
this.creator.toBytes(),
|
|
123
|
+
amount,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Calculate current market cap in SOL
|
|
129
|
+
*/
|
|
130
|
+
getMarketCapSol(): number {
|
|
131
|
+
if (this.virtualTokenReserves === 0) {
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const pricePerToken = this.virtualSolReserves / this.virtualTokenReserves;
|
|
136
|
+
return (pricePerToken * this.tokenTotalSupply) / 1e9;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Calculate price to buy out all remaining tokens
|
|
141
|
+
*/
|
|
142
|
+
getBuyOutPrice(amount: number): number {
|
|
143
|
+
if (this.complete) {
|
|
144
|
+
throw new Error('Curve is complete');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Rough estimate: current price * amount
|
|
148
|
+
if (this.virtualTokenReserves === 0) {
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const priceRatio = this.virtualSolReserves / this.virtualTokenReserves;
|
|
153
|
+
return Math.floor(priceRatio * amount);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Calculate the current token price in SOL.
|
|
158
|
+
* 100% from Rust: src/common/bonding_curve.rs get_token_price
|
|
159
|
+
*/
|
|
160
|
+
getTokenPrice(): number {
|
|
161
|
+
const vSol = this.virtualSolReserves / 100_000_000.0;
|
|
162
|
+
const vTokens = this.virtualTokenReserves / 100_000.0;
|
|
163
|
+
if (vTokens === 0) {
|
|
164
|
+
return 0.0;
|
|
165
|
+
}
|
|
166
|
+
return vSol / vTokens;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Calculate the final market cap in SOL after all tokens are sold.
|
|
171
|
+
* 100% from Rust: src/common/bonding_curve.rs get_final_market_cap_sol
|
|
172
|
+
*/
|
|
173
|
+
getFinalMarketCapSol(feeBasisPoints: number = 95): bigint {
|
|
174
|
+
const totalSellValue = this.getBuyOutPriceInternal(this.realTokenReserves, feeBasisPoints);
|
|
175
|
+
const totalVirtualValue = BigInt(this.virtualSolReserves) + BigInt(totalSellValue);
|
|
176
|
+
const totalVirtualTokens = BigInt(this.virtualTokenReserves) - BigInt(this.realTokenReserves);
|
|
177
|
+
|
|
178
|
+
if (totalVirtualTokens === 0n) {
|
|
179
|
+
return 0n;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return (BigInt(this.tokenTotalSupply) * totalVirtualValue) / totalVirtualTokens;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private getBuyOutPriceInternal(amount: number, feeBasisPoints: number): number {
|
|
186
|
+
const solTokens = Math.max(amount, this.realSolReserves);
|
|
187
|
+
|
|
188
|
+
if (this.virtualTokenReserves <= solTokens) {
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const totalSellValue = Number((BigInt(solTokens) * BigInt(this.virtualSolReserves)) / (BigInt(this.virtualTokenReserves) - BigInt(solTokens))) + 1;
|
|
193
|
+
const fee = Math.floor((totalSellValue * feeBasisPoints) / 10000);
|
|
194
|
+
|
|
195
|
+
return totalSellValue + fee;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ===== Decoding Functions - from Rust: src/instruction/utils/pumpfun.rs =====
|
|
200
|
+
|
|
201
|
+
export const BONDING_CURVE_ACCOUNT_SIZE = 8 + 8 + 8 + 8 + 8 + 8 + 1 + 32 + 1 + 1; // 77 bytes after discriminator
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Decode a BondingCurveAccount from on-chain account data.
|
|
205
|
+
* 100% from Rust: src/common/bonding_curve.rs
|
|
206
|
+
*/
|
|
207
|
+
export function decodeBondingCurveAccount(data: Buffer, account?: PublicKey): BondingCurveAccount | null {
|
|
208
|
+
if (data.length < BONDING_CURVE_ACCOUNT_SIZE) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
let offset = 0;
|
|
214
|
+
|
|
215
|
+
// Check if data starts with discriminator (8 bytes)
|
|
216
|
+
if (data.length >= 8 + BONDING_CURVE_ACCOUNT_SIZE) {
|
|
217
|
+
// Skip discriminator
|
|
218
|
+
offset = 8;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// virtual_token_reserves: u64
|
|
222
|
+
const virtualTokenReserves = Number(data.readBigUInt64LE(offset));
|
|
223
|
+
offset += 8;
|
|
224
|
+
|
|
225
|
+
// virtual_sol_reserves: u64
|
|
226
|
+
const virtualSolReserves = Number(data.readBigUInt64LE(offset));
|
|
227
|
+
offset += 8;
|
|
228
|
+
|
|
229
|
+
// real_token_reserves: u64
|
|
230
|
+
const realTokenReserves = Number(data.readBigUInt64LE(offset));
|
|
231
|
+
offset += 8;
|
|
232
|
+
|
|
233
|
+
// real_sol_reserves: u64
|
|
234
|
+
const realSolReserves = Number(data.readBigUInt64LE(offset));
|
|
235
|
+
offset += 8;
|
|
236
|
+
|
|
237
|
+
// token_total_supply: u64
|
|
238
|
+
const tokenTotalSupply = Number(data.readBigUInt64LE(offset));
|
|
239
|
+
offset += 8;
|
|
240
|
+
|
|
241
|
+
// complete: bool
|
|
242
|
+
const complete = data.readUInt8(offset) === 1;
|
|
243
|
+
offset += 1;
|
|
244
|
+
|
|
245
|
+
// creator: Pubkey (32 bytes)
|
|
246
|
+
const creator = new PublicKey(data.subarray(offset, offset + 32));
|
|
247
|
+
offset += 32;
|
|
248
|
+
|
|
249
|
+
// is_mayhem_mode: bool
|
|
250
|
+
const isMayhemMode = data.readUInt8(offset) === 1;
|
|
251
|
+
offset += 1;
|
|
252
|
+
|
|
253
|
+
// is_cashback_coin: bool
|
|
254
|
+
const isCashbackCoin = data.readUInt8(offset) === 1;
|
|
255
|
+
|
|
256
|
+
return new BondingCurveAccount({
|
|
257
|
+
discriminator: 0,
|
|
258
|
+
account: account ?? PublicKey.default,
|
|
259
|
+
virtualTokenReserves,
|
|
260
|
+
virtualSolReserves,
|
|
261
|
+
realTokenReserves,
|
|
262
|
+
realSolReserves,
|
|
263
|
+
tokenTotalSupply,
|
|
264
|
+
complete,
|
|
265
|
+
creator,
|
|
266
|
+
isMayhemMode,
|
|
267
|
+
isCashbackCoin,
|
|
268
|
+
});
|
|
269
|
+
} catch {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute Budget Manager - 100% port from Rust: src/trading/common/compute_budget_manager.rs
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for managing compute budget instructions:
|
|
5
|
+
* - Setting compute unit price
|
|
6
|
+
* - Setting compute unit limit
|
|
7
|
+
* - Caching for performance
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { TransactionInstruction, PublicKey } from '@solana/web3.js';
|
|
11
|
+
|
|
12
|
+
// ===== Constants =====
|
|
13
|
+
|
|
14
|
+
const COMPUTE_BUDGET_PROGRAM_ID = new PublicKey('ComputeBudget111111111111111111111111111111');
|
|
15
|
+
|
|
16
|
+
// Instruction types for Compute Budget program
|
|
17
|
+
const COMPUTE_BUDGET_INSTRUCTIONS = {
|
|
18
|
+
REQUEST_UNITS: 0,
|
|
19
|
+
REQUEST_HEAP_FRAME: 1,
|
|
20
|
+
SET_COMPUTE_UNIT_LIMIT: 2,
|
|
21
|
+
SET_COMPUTE_UNIT_PRICE: 3,
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
// ===== Cache =====
|
|
25
|
+
|
|
26
|
+
interface ComputeBudgetCacheKey {
|
|
27
|
+
unitPrice: bigint;
|
|
28
|
+
unitLimit: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const computeBudgetCache = new Map<string, TransactionInstruction[]>();
|
|
32
|
+
|
|
33
|
+
function getCacheKey(key: ComputeBudgetCacheKey): string {
|
|
34
|
+
return `${key.unitPrice}:${key.unitLimit}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ===== Instruction Builders =====
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create Set Compute Unit Price instruction
|
|
41
|
+
*/
|
|
42
|
+
function setComputeUnitPrice(price: bigint): TransactionInstruction {
|
|
43
|
+
const data = Buffer.alloc(9);
|
|
44
|
+
data.writeUInt8(COMPUTE_BUDGET_INSTRUCTIONS.SET_COMPUTE_UNIT_PRICE, 0);
|
|
45
|
+
data.writeBigUInt64LE(price, 1);
|
|
46
|
+
|
|
47
|
+
return new TransactionInstruction({
|
|
48
|
+
keys: [],
|
|
49
|
+
programId: COMPUTE_BUDGET_PROGRAM_ID,
|
|
50
|
+
data,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create Set Compute Unit Limit instruction
|
|
56
|
+
*/
|
|
57
|
+
function setComputeUnitLimit(limit: number): TransactionInstruction {
|
|
58
|
+
const data = Buffer.alloc(5);
|
|
59
|
+
data.writeUInt8(COMPUTE_BUDGET_INSTRUCTIONS.SET_COMPUTE_UNIT_LIMIT, 0);
|
|
60
|
+
data.writeUInt32LE(limit, 1);
|
|
61
|
+
|
|
62
|
+
return new TransactionInstruction({
|
|
63
|
+
keys: [],
|
|
64
|
+
programId: COMPUTE_BUDGET_PROGRAM_ID,
|
|
65
|
+
data,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ===== Public Functions =====
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Extend instructions array with compute budget instructions
|
|
73
|
+
* Uses caching for performance
|
|
74
|
+
* 100% from Rust: src/trading/common/compute_budget_manager.rs extend_compute_budget_instructions
|
|
75
|
+
*/
|
|
76
|
+
export function extendComputeBudgetInstructions(
|
|
77
|
+
instructions: TransactionInstruction[],
|
|
78
|
+
unitPrice: bigint,
|
|
79
|
+
unitLimit: number
|
|
80
|
+
): void {
|
|
81
|
+
const cacheKey: ComputeBudgetCacheKey = { unitPrice, unitLimit };
|
|
82
|
+
const key = getCacheKey(cacheKey);
|
|
83
|
+
|
|
84
|
+
let cachedInstructions = computeBudgetCache.get(key);
|
|
85
|
+
|
|
86
|
+
if (!cachedInstructions) {
|
|
87
|
+
cachedInstructions = [];
|
|
88
|
+
|
|
89
|
+
if (unitPrice > BigInt(0)) {
|
|
90
|
+
cachedInstructions.push(setComputeUnitPrice(unitPrice));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (unitLimit > 0) {
|
|
94
|
+
cachedInstructions.push(setComputeUnitLimit(unitLimit));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
computeBudgetCache.set(key, cachedInstructions);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
instructions.push(...cachedInstructions);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Get compute budget instructions as array
|
|
105
|
+
* 100% from Rust: src/trading/common/compute_budget_manager.rs compute_budget_instructions
|
|
106
|
+
*/
|
|
107
|
+
export function computeBudgetInstructions(
|
|
108
|
+
unitPrice: bigint,
|
|
109
|
+
unitLimit: number
|
|
110
|
+
): TransactionInstruction[] {
|
|
111
|
+
const cacheKey: ComputeBudgetCacheKey = { unitPrice, unitLimit };
|
|
112
|
+
const key = getCacheKey(cacheKey);
|
|
113
|
+
|
|
114
|
+
let cachedInstructions = computeBudgetCache.get(key);
|
|
115
|
+
|
|
116
|
+
if (!cachedInstructions) {
|
|
117
|
+
cachedInstructions = [];
|
|
118
|
+
|
|
119
|
+
if (unitPrice > BigInt(0)) {
|
|
120
|
+
cachedInstructions.push(setComputeUnitPrice(unitPrice));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (unitLimit > 0) {
|
|
124
|
+
cachedInstructions.push(setComputeUnitLimit(unitLimit));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
computeBudgetCache.set(key, cachedInstructions);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return [...cachedInstructions]; // Return copy
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Clear the compute budget cache
|
|
135
|
+
*/
|
|
136
|
+
export function clearComputeBudgetCache(): void {
|
|
137
|
+
computeBudgetCache.clear();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ===== Predefined Compute Budgets =====
|
|
141
|
+
|
|
142
|
+
export const COMPUTE_BUDGET_PRESETS = {
|
|
143
|
+
LOW: { unitLimit: 100_000, unitPrice: BigInt(1_000) },
|
|
144
|
+
MEDIUM: { unitLimit: 200_000, unitPrice: BigInt(10_000) },
|
|
145
|
+
HIGH: { unitLimit: 400_000, unitPrice: BigInt(50_000) },
|
|
146
|
+
VERY_HIGH: { unitLimit: 800_000, unitPrice: BigInt(100_000) },
|
|
147
|
+
MAX: { unitLimit: 1_400_000, unitPrice: BigInt(200_000) },
|
|
148
|
+
} as const;
|