1/* 2 [PEÅNE KOMPENDIUM SYSTEMU SDK128] 3 MODUÅ: solana_lite_manager_v3.js 4 LOGIKA: Lekki manager Solana (Browser-Lite) bazujÄ cy na MASTER LOGIC z SDK128. 5 CEL: ZgodnoÅÄ 1:1 z price_pool_chartSDK128.js i utilsSDK128.js. 6*/ 7 8const PUMP_PROGRAM_ID = new solanaWeb3.PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"); 9const PUMP_AMM_PROGRAM_ID = new solanaWeb3.PublicKey("pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA"); 10const WSOL_MINT = new solanaWeb3.PublicKey("So11111111111111111111111111111111111111112"); 11const ASSOCIATED_TOKEN_PROGRAM_ID = new solanaWeb3.PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); 12const TOKEN_PROGRAM_ID = new solanaWeb3.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); 13 14const METADATA_PROGRAM_ID = new solanaWeb3.PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"); 15 16class SolanaLiteManagerV3 { 17 constructor(rpcUrl) { 18 this.connection = new solanaWeb3.Connection(rpcUrl, 'confirmed'); 19 } 20 21 logUI(msg, type = 'info') { 22 console.log(`[LiteManager] ${msg}`); 23 if (window.onLiteLog) window.onLiteLog(msg, type); 24 } 25 26 async getMintMetadata(mint) { 27 try { 28 const pubkey = new solanaWeb3.PublicKey(mint); 29 const info = await this.connection.getParsedAccountInfo(pubkey); 30 let decimals = 6; 31 if (info.value && info.value.data.parsed) { 32 decimals = info.value.data.parsed.info.decimals; 33 } 34 35 const meta = await this.getTokenMetadata(mint); 36 return { decimals, name: meta.name, symbol: meta.symbol }; 37 } catch (e) { 38 return { decimals: 6, name: "Unknown", symbol: "???" }; 39 } 40 } 41 42 async getTokenMetadata(mint) { 43 /* [MASTER LOGIC SYNC: utilsSDK128.js] */ 44 try { 45 this.logUI(`Fetching metadata for: ${mint}...`); 46 const mintPk = new solanaWeb3.PublicKey(mint); 47 const mintInfo = await this.connection.getAccountInfo(mintPk); 48 if (!mintInfo) { 49 this.logUI(`Mint account not found!`, 'error'); 50 return { name: "N/A", symbol: "N/A" }; 51 } 52 53 // 1. Token-2022 Extensions Brute-force 54 if (mintInfo.owner.toBase58() === "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb") { 55 this.logUI(`Token-2022 detected, checking extensions...`); 56 for (let i = 165; i < mintInfo.data.length - 8; i++) { 57 if (mintInfo.data[i] === 0x13 && mintInfo.data[i+1] === 0x00) { 58 try { 59 const view = new DataView(mintInfo.data.buffer, mintInfo.data.byteOffset + i + 2, 2); 60 const length = view.getUint16(0, true); 61 if (i + 4 + length <= mintInfo.data.length) { 62 const metadataBuffer = mintInfo.data.slice(i + 4, i + 4 + length); 63 let mOffset = 64; 64 const nView = new DataView(metadataBuffer.buffer, metadataBuffer.byteOffset + mOffset, 4); 65 const nameLen = nView.getUint32(0, true); 66 const name = new TextDecoder().decode(metadataBuffer.slice(mOffset + 4, mOffset + 4 + nameLen)).replace(/[\x00-\x1F\x7F-\x9F]/g, "").trim(); 67 mOffset += 4 + nameLen; 68 const sView = new DataView(metadataBuffer.buffer, metadataBuffer.byteOffset + mOffset, 4); 69 const symbolLen = sView.getUint32(0, true); 70 const symbol = new TextDecoder().decode(metadataBuffer.slice(mOffset + 4, mOffset + 4 + symbolLen)).replace(/[\x00-\x1F\x7F-\x9F]/g, "").trim(); 71 if (name || symbol) { 72 this.logUI(`Found Token-2022 Metadata: ${name} (${symbol})`, 'success'); 73 return { name: name || "Unknown", symbol: symbol || "???" }; 74 } 75 } 76 } catch (err) { 77 this.logUI(`Token-2022 Parse Error: ${err.message}`, 'error'); 78 } 79 } 80 } 81 } 82 83 // 2. Metaplex Metadata V1 84 this.logUI(`Checking Metaplex Metadata PDA...`); 85 const [pda] = solanaWeb3.PublicKey.findProgramAddressSync( 86 [new TextEncoder().encode("metadata"), METADATA_PROGRAM_ID.toBuffer(), mintPk.toBuffer()], 87 METADATA_PROGRAM_ID 88 ); 89 90 this.logUI(`PDA derived: ${pda.toBase58()}`); 91 const pdaInfo = await this.connection.getAccountInfo(pda); 92 if (pdaInfo) { 93 this.logUI(`Metaplex Metadata found! Decoding...`, 'success'); 94 // Name at 69, Symbol at 105 (Metaplex V1 layout with 4-byte prefixes) 95 const name = new TextDecoder().decode(pdaInfo.data.slice(69, 101)).replace(/[\x00-\x1F\x7F-\x9F]/g, "").trim(); 96 const symbol = new TextDecoder().decode(pdaInfo.data.slice(105, 115)).replace(/[\x00-\x1F\x7F-\x9F]/g, "").trim(); 97 this.logUI(`Decoded: ${name} / ${symbol}`, 'success'); 98 return { name: name || "Unknown", symbol: symbol || "???" }; 99 } else { 100 this.logUI(`Metaplex Metadata PDA not found.`, 'warn'); 101 } 102 103 return { name: "Unknown", symbol: "???" }; 104 } catch (e) { 105 this.logUI(`Metadata Error: ${e.message}`, 'error'); 106 console.error(e); 107 return { name: "Unknown", symbol: "???" }; 108 } 109 } 110 111 async getMintSupply(mint) { 112 try { 113 const mintPk = new solanaWeb3.PublicKey(mint); 114 // Use getParsedAccountInfo as it's often cached better by RPCs than raw getAccountInfo 115 const info = await this.connection.getParsedAccountInfo(mintPk); 116 if (info.value && info.value.data.parsed) { 117 return BigInt(info.value.data.parsed.info.supply); 118 } 119 // Fallback to raw if parsing failed 120 if (info.value) { 121 return this.readBigUInt64LE(info.value.data, 36); 122 } 123 } catch (e) { 124 console.error("Error fetching mint supply:", e); 125 } 126 return 0n; 127 } 128 129 // --- PDA DERIVATION (MATCHING SDK128) --- 130 131 getBondingCurvePda(mint) { 132 const mintPk = new solanaWeb3.PublicKey(mint); 133 return solanaWeb3.PublicKey.findProgramAddressSync( 134 [new TextEncoder().encode('bonding-curve'), mintPk.toBytes()], 135 PUMP_PROGRAM_ID 136 )[0]; 137 } 138 139 getBondingCurveV2Pda(mint) { 140 const mintPk = new solanaWeb3.PublicKey(mint); 141 return solanaWeb3.PublicKey.findProgramAddressSync( 142 [new TextEncoder().encode('bonding-curve-v2'), mintPk.toBytes()], 143 PUMP_PROGRAM_ID 144 )[0]; 145 } 146 147 getAuthorityPda(mint) { 148 const mintPk = new solanaWeb3.PublicKey(mint); 149 return solanaWeb3.PublicKey.findProgramAddressSync( 150 [new TextEncoder().encode('pool-authority'), mintPk.toBytes()], 151 PUMP_PROGRAM_ID 152 )[0]; 153 } 154 155 getPoolV1Pda(mint) { 156 const mintPk = new solanaWeb3.PublicKey(mint); 157 const authority = this.getAuthorityPda(mint); 158 // Canonical Pump.fun AMM Pool (V1) - Correct Seeds from SDK 159 const index_buf = new Uint8Array(2); 160 // index 0 LE 161 index_buf[0] = 0; 162 index_buf[1] = 0; 163 164 return solanaWeb3.PublicKey.findProgramAddressSync( 165 [ 166 new TextEncoder().encode('pool'), 167 index_buf, 168 authority.toBuffer(), 169 mintPk.toBuffer(), 170 WSOL_MINT.toBuffer() 171 ], 172 PUMP_AMM_PROGRAM_ID 173 )[0]; 174 } 175 176 getPoolV2Pda(mint) { 177 const mintPk = new solanaWeb3.PublicKey(mint); 178 // Alternative Pump.fun AMM Pool (V2) 179 return solanaWeb3.PublicKey.findProgramAddressSync( 180 [new TextEncoder().encode('pool-v2'), mintPk.toBytes()], 181 PUMP_AMM_PROGRAM_ID 182 )[0]; 183 } 184 185 getAta(mint, owner, programId = TOKEN_PROGRAM_ID) { 186 const mintPk = new solanaWeb3.PublicKey(mint); 187 const ownerPk = new solanaWeb3.PublicKey(owner); 188 const progPk = new solanaWeb3.PublicKey(programId); 189 return solanaWeb3.PublicKey.findProgramAddressSync( 190 [ownerPk.toBytes(), progPk.toBytes(), mintPk.toBytes()], 191 ASSOCIATED_TOKEN_PROGRAM_ID 192 )[0]; 193 } 194 195 // --- DATA DECODING (MATCHING SDK128) --- 196 197 decodeBondingCurve(data) { 198 // Offset 8 for discriminator 199 const virtualTokenReserves = this.readBigUInt64LE(data, 8); 200 const virtualSolReserves = this.readBigUInt64LE(data, 16); 201 const realTokenReserves = this.readBigUInt64LE(data, 24); 202 const realSolReserves = this.readBigUInt64LE(data, 32); 203 const tokenTotalSupply = this.readBigUInt64LE(data, 40); 204 const complete = data[48] !== 0; 205 206 return { 207 virtualTokenReserves, 208 virtualSolReserves, 209 realTokenReserves, 210 realSolReserves, 211 tokenTotalSupply, 212 complete 213 }; 214 } 215 216 decodeTokenAmount(data) { 217 // SPL Token Account balance is at offset 64 (8 bytes) 218 return this.readBigUInt64LE(data, 64); 219 } 220 221 readBigUInt64LE(buffer, offset) { 222 const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); 223 return view.getBigUint64(offset, true); 224 } 225 226 // --- PRICE CALCULATION (MATCHING price_pool_chartSDK128.js) --- 227 228 calculatePrice(phase, data, decimals = 6) { 229 if (phase === 'CURVE') { 230 const vS = Number(data.virtualSolReserves) / 1e9; 231 const vT = Number(data.virtualTokenReserves) / Math.pow(10, decimals); 232 return vT > 0 ? vS / vT : 0; 233 } else if (phase === 'AMM') { 234 const bNum = Number(data.baseAmount) / Math.pow(10, decimals);
235 const qNum = Number(data.quoteAmount) / 1e9; 236 return bNum > 0 ? qNum / bNum : 0; 237 } 238 return 0; 239 } 240 241 async fetchFullAmmState(mint, silent = false) { 242 const mintPk = new solanaWeb3.PublicKey(mint); 243 const poolPda = this.getPoolV1Pda(mint); 244 245 let tokenProgram = TOKEN_PROGRAM_ID; 246 try { 247 const mInfo = await this.connection.getAccountInfo(mintPk); 248 if (mInfo) tokenProgram = mInfo.owner; 249 } catch (e) {} 250 251 const poolBaseAta = this.getAta(mint, poolPda, tokenProgram); 252 const poolQuoteAta = this.getAta(WSOL_MINT, poolPda, TOKEN_PROGRAM_ID); 253 254 try { 255 const [baseInfo, quoteInfo, mintInfo] = await Promise.all([ 256 this.connection.getAccountInfo(poolBaseAta), 257 this.connection.getAccountInfo(poolQuoteAta), 258 this.connection.getAccountInfo(mintPk) 259 ]); 260 261 let totalSupply = 0n; 262 if (mintInfo) { 263 // Supply is at offset 36 (8 bytes) 264 totalSupply = this.readBigUInt64LE(mintInfo.data, 36); 265 } 266 267 if (baseInfo && quoteInfo) { 268 const baseAmount = this.decodeTokenAmount(baseInfo.data); 269 const quoteAmount = this.decodeTokenAmount(quoteInfo.data); 270 return { 271 poolPda, 272 baseAmount, 273 quoteAmount, 274 poolBaseAta, 275 poolQuoteAta, 276 tokenProgram, 277 totalSupply 278 }; 279 } 280 } catch (e) { 281 if (!silent) console.error("Error fetching AMM state:", e); 282 } 283 return null; 284 } 285 286 // --- PHASE DETECTION (MATCHING detectTokenPhase in utilsSDK128.js) --- 287 288 async detectTokenPhase(mint) { 289 const logUI = (msg, type = 'info') => { 290 console.log(`[LiteManager] ${msg}`); 291 if (window.onLiteLog) window.onLiteLog(msg, type); 292 }; 293 294 logUI(`=== Phase Detection for: ${mint} ===`); 295 const mintPk = new solanaWeb3.PublicKey(mint); 296 297 let tokenProgram = TOKEN_PROGRAM_ID; 298 try { 299 const mInfo = await this.connection.getAccountInfo(mintPk); 300 if (mInfo) { 301 tokenProgram = mInfo.owner; 302 logUI(`Mint Owner: ${tokenProgram.toBase58()}`); 303 } 304 } catch (e) { 305 logUI(`Warning: Could not fetch mint info (RPC?), defaulting to Tokenkeg...`); 306 } 307 308 // --- PHASE SEQUENCE --- 309 310 // 1. Sprawdź Bonding Curve V1 311 const bcPda = this.getBondingCurvePda(mint); 312 logUI(`Checking BC V1: ${bcPda.toBase58()}`); 313 try { 314 const bcInfo = await this.connection.getAccountInfo(bcPda); 315 if (bcInfo) { 316 const decoded = this.decodeBondingCurve(bcInfo.data); 317 if (!decoded.complete) { 318 logUI(`Phase: CURVE (V1) Found!`, 'success'); 319 return { phase: 'CURVE', data: decoded, pda: bcPda, tokenProgram, version: 'V1' }; 320 } 321 logUI(`BC V1 Complete...`); 322 } 323 } catch (e) {} 324 325 // 2. Sprawdź Bonding Curve V2 326 const bcV2Pda = this.getBondingCurveV2Pda(mint); 327 logUI(`Checking BC V2: ${bcV2Pda.toBase58()}`); 328 try { 329 const bcV2Info = await this.connection.getAccountInfo(bcV2Pda); 330 if (bcV2Info) { 331 const decoded = this.decodeBondingCurve(bcV2Info.data); 332 if (!decoded.complete) { 333 logUI(`Phase: CURVE (V2) Found!`, 'success'); 334 return { phase: 'CURVE', data: decoded, pda: bcV2Pda, tokenProgram, version: 'V2' }; 335 } 336 logUI(`BC V2 Complete...`); 337 } 338 } catch (e) {} 339 340 // 3. Sprawdź AMM V1 (Canonical) 341 const poolV1Pda = this.getPoolV1Pda(mint); 342 logUI(`Checking AMM V1 (Canonical): ${poolV1Pda.toBase58()}`); 343 try { 344 const poolV1State = await this.fetchFullAmmState(mint, true);
345 if (poolV1State) { 346 logUI(`Phase: AMM (V1) Found!`, 'success'); 347 return { phase: 'AMM', data: poolV1State, pda: poolV1Pda, tokenProgram, version: 'V1' }; 348 } 349 } catch (e) {} 350 351 // 4. Sprawdź AMM V2 (Pool-V2) 352 const poolV2Pda = this.getPoolV2Pda(mint); 353 logUI(`Checking AMM V2 (Pool-V2): ${poolV2Pda.toBase58()}`); 354 try { 355 const poolV2Info = await this.connection.getAccountInfo(poolV2Pda); 356 if (poolV2Info) { 357 logUI(`Phase: AMM (V2) Found!`, 'success'); 358 // Dla V2 spróbuj też pobraÄ balansy jeÅli ATA istniejÄ 359 const poolV2State = await this.fetchFullAmmState(mint, true); 360 return { phase: 'AMM', data: poolV2State || { poolPda: poolV2Pda }, pda: poolV2Pda, tokenProgram, version: 'V2' }; 361 } 362 } catch (e) {} 363 364 logUI(`No active phase found (UNKNOWN). Check if RPC supports Token-2022 Accounts.`, 'error'); 365 return { phase: 'UNKNOWN' }; 366 } 367 368 subscribeToAccount(pubkey, callback) { 369 return this.connection.onAccountChange( 370 new solanaWeb3.PublicKey(pubkey), 371 (info) => callback(info), 372 'confirmed' 373 ); 374 } 375 376 async getSolPrice() { 377 try { 378 const url = `/api/sol-price`; 379 const resp = await fetch(url); 380 const data = await resp.json(); 381 // Jupiter V3 ticker structure: { MINT: { usdPrice: N, ... } } 382 return data["So11111111111111111111111111111111111111112"].usdPrice; 383 } catch (e) { 384 console.warn("SOL Price fetch error:", e); 385 return null; 386 } 387 } 388}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.