Skip to main content
Glama
monostate

100ms Raydium Sniper MCP

by monostate
amm-decoder.js8.96 kB
import { PublicKey } from "@solana/web3.js"; import BN from 'bn.js'; const AMM_ACCOUNT_LAYOUT = { VERSION_OFFSET: 0, STATUS_OFFSET: 1, NONCE_OFFSET: 8, MAX_ORDER_OFFSET: 16, DEPTH_OFFSET: 24, BASE_DECIMAL_OFFSET: 32, QUOTE_DECIMAL_OFFSET: 40, STATE_OFFSET: 48, RESET_FLAG_OFFSET: 56, U64_FIELDS: [ { name: 'minSize', offset: 64 }, { name: 'volMaxCutRatio', offset: 72 }, { name: 'amountWaveRatio', offset: 80 }, { name: 'baseLotSize', offset: 88 }, { name: 'quoteLotSize', offset: 96 }, { name: 'minSeparateNumerator', offset: 104 }, { name: 'minSeparateDenominator', offset: 112 }, { name: 'tradeFeeNumerator', offset: 120 }, { name: 'tradeFeeDenominator', offset: 128 }, { name: 'pnlNumerator', offset: 136 }, { name: 'pnlDenominator', offset: 144 }, { name: 'swapFeeNumerator', offset: 152 }, { name: 'swapFeeDenominator', offset: 160 }, { name: 'baseNeedTakePnl', offset: 168 }, { name: 'quoteNeedTakePnl', offset: 176 }, { name: 'quoteTotalPnl', offset: 184 }, { name: 'baseTotalPnl', offset: 192 }, { name: 'systemDecimalValue', offset: 200 }, { name: 'minPriceMultiplier', offset: 208 }, { name: 'maxPriceMultiplier', offset: 216 }, { name: 'swapBaseInAmount', offset: 224 }, { name: 'swapQuoteOutAmount', offset: 232 }, { name: 'swapBase2QuoteFee', offset: 240 }, { name: 'swapQuoteInAmount', offset: 248 }, { name: 'swapBaseOutAmount', offset: 256 }, { name: 'swapQuote2BaseFee', offset: 264 }, { name: 'poolOpenTime', offset: 272 }, { name: 'punishPcAmount', offset: 280 }, { name: 'punishCoinAmount', offset: 288 }, { name: 'orderbookToInitTime', offset: 296 }, { name: 'lpReserve', offset: 304 } ], PUBKEY_FIELDS: [ { name: 'baseVault', offset: 336 }, { name: 'quoteVault', offset: 368 }, { name: 'baseMint', offset: 400 }, { name: 'quoteMint', offset: 432 }, { name: 'lpMint', offset: 464 }, { name: 'openOrders', offset: 496 }, { name: 'marketId', offset: 528 }, { name: 'marketProgramId', offset: 560 }, { name: 'targetOrders', offset: 592 }, { name: 'serumBids', offset: 688 }, { name: 'serumAsks', offset: 720 }, { name: 'serumEventQueue', offset: 752 }, { name: 'serumCoinVault', offset: 784 }, { name: 'serumPcVault', offset: 816 }, { name: 'serumVaultSigner', offset: 848 } ] }; function readUint8(buffer, offset) { return buffer[offset]; } function readUint64LE(buffer, offset) { const slice = buffer.slice(offset, offset + 8); return new BN(slice, 'le'); } const publicKeyCache = new Map(); function getCachedPublicKey(key) { const cacheKey = typeof key === 'string' ? key : key.toString('hex'); if (!publicKeyCache.has(cacheKey)) { publicKeyCache.set(cacheKey, new PublicKey(key)); } return publicKeyCache.get(cacheKey); } const BASEMINT_OFFSET = AMM_ACCOUNT_LAYOUT.PUBKEY_FIELDS.find(f => f.name === 'baseMint').offset; const QUOTEMINT_OFFSET = AMM_ACCOUNT_LAYOUT.PUBKEY_FIELDS.find(f => f.name === 'quoteMint').offset; function readPubkey(buffer, offset) { try { const slice = buffer.slice(offset, offset + 32); return getCachedPublicKey(slice); } catch (error) { return getCachedPublicKey("11111111111111111111111111111111"); } } function toBuffer(data) { if (Buffer.isBuffer(data)) return data; try { return Buffer.from(data, 'base64'); } catch { return Buffer.from(data); } } export function decodeAmmMints(data) { try { const buffer = toBuffer(data); if (!isAmmAccountData(buffer)) return null; const baseMint = readPubkey(buffer, BASEMINT_OFFSET); const quoteMint = readPubkey(buffer, QUOTEMINT_OFFSET); return { baseMint: baseMint.toBase58(), quoteMint: quoteMint.toBase58() }; } catch (error) { return null; } } const base64Buffer = Buffer.allocUnsafe(3000); export function decodeAmmAccount(data) { try { const buffer = toBuffer(data); if (!isAmmAccountData(buffer)) return null; return decodeBuffer(buffer); } catch (error) { return null; } } function decodeBuffer(buffer) { try { const decoded = { version: readUint8(buffer, AMM_ACCOUNT_LAYOUT.VERSION_OFFSET), status: readUint8(buffer, AMM_ACCOUNT_LAYOUT.STATUS_OFFSET), nonce: readUint8(buffer, AMM_ACCOUNT_LAYOUT.NONCE_OFFSET), maxOrder: readUint8(buffer, AMM_ACCOUNT_LAYOUT.MAX_ORDER_OFFSET), depth: readUint8(buffer, AMM_ACCOUNT_LAYOUT.DEPTH_OFFSET), baseDecimal: readUint8(buffer, AMM_ACCOUNT_LAYOUT.BASE_DECIMAL_OFFSET), quoteDecimal: readUint8(buffer, AMM_ACCOUNT_LAYOUT.QUOTE_DECIMAL_OFFSET), state: readUint8(buffer, AMM_ACCOUNT_LAYOUT.STATE_OFFSET), resetFlag: readUint8(buffer, AMM_ACCOUNT_LAYOUT.RESET_FLAG_OFFSET) }; for (const field of AMM_ACCOUNT_LAYOUT.U64_FIELDS) { decoded[field.name] = readUint64LE(buffer, field.offset).toString(); } for (const field of AMM_ACCOUNT_LAYOUT.PUBKEY_FIELDS) { decoded[field.name] = readPubkey(buffer, field.offset).toBase58(); } return { ...decoded, version: parseInt(decoded.version), status: parseInt(decoded.status), nonce: parseInt(decoded.nonce), maxOrder: parseInt(decoded.maxOrder), depth: parseInt(decoded.depth), baseDecimal: parseInt(decoded.baseDecimal), quoteDecimal: parseInt(decoded.quoteDecimal), state: parseInt(decoded.state), resetFlag: parseInt(decoded.resetFlag), minSize: decoded.minSize, volMaxCutRatio: parseInt(decoded.volMaxCutRatio), amountWaveRatio: parseInt(decoded.amountWaveRatio), baseLotSize: decoded.baseLotSize, quoteLotSize: decoded.quoteLotSize, minSeparateNumerator: parseInt(decoded.minSeparateNumerator), minSeparateDenominator: parseInt(decoded.minSeparateDenominator), tradeFeeNumerator: parseInt(decoded.tradeFeeNumerator), tradeFeeDenominator: parseInt(decoded.tradeFeeDenominator), swapFeeNumerator: parseInt(decoded.swapFeeNumerator), swapFeeDenominator: parseInt(decoded.swapFeeDenominator), pnlNumerator: parseInt(decoded.pnlNumerator), pnlDenominator: parseInt(decoded.pnlDenominator), baseNeedTakePnl: decoded.baseNeedTakePnl, quoteNeedTakePnl: decoded.quoteNeedTakePnl, quoteTotalPnl: decoded.quoteTotalPnl, baseTotalPnl: decoded.baseTotalPnl, systemDecimalValue: decoded.systemDecimalValue, minPriceMultiplier: parseInt(decoded.minPriceMultiplier), maxPriceMultiplier: parseInt(decoded.maxPriceMultiplier), swapBaseInAmount: decoded.swapBaseInAmount, swapQuoteOutAmount: decoded.swapQuoteOutAmount, swapBase2QuoteFee: decoded.swapBase2QuoteFee, swapQuoteInAmount: decoded.swapQuoteInAmount, swapBaseOutAmount: decoded.swapBaseOutAmount, swapQuote2BaseFee: decoded.swapQuote2BaseFee, poolOpenTime: decoded.poolOpenTime, punishPcAmount: decoded.punishPcAmount, punishCoinAmount: decoded.punishCoinAmount, orderbookToInitTime: decoded.orderbookToInitTime, lpReserve: decoded.lpReserve, baseVault: decoded.baseVault, quoteVault: decoded.quoteVault, baseMint: decoded.baseMint, quoteMint: decoded.quoteMint, lpMint: decoded.lpMint, openOrders: decoded.openOrders, marketId: decoded.marketId, marketProgramId: decoded.marketProgramId, targetOrders: decoded.targetOrders, serumBids: decoded.serumBids, serumAsks: decoded.serumAsks, serumEventQueue: decoded.serumEventQueue, serumCoinVault: decoded.serumCoinVault, serumPcVault: decoded.serumPcVault, serumVaultSigner: decoded.serumVaultSigner }; } catch (error) { return null; } } export function isAmmAccountData(data) { try { if (!data || data.length < 752) return false; const version = data[AMM_ACCOUNT_LAYOUT.VERSION_OFFSET]; const nonce = data[AMM_ACCOUNT_LAYOUT.NONCE_OFFSET]; return version === 6 && nonce === 254; } catch (error) { return false; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/monostate/100ms-SPL-Token-Sniper-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server