Created
June 22, 2024 19:35
-
-
Save rubpy/171fdd565569191b4fc7ba9555e4564f to your computer and use it in GitHub Desktop.
Tracking changes in Pump.fun global state (initialVirtualTokenReserves, initialVirtualSolReserves, initialRealTokenReserves, tokenTotalSupply, feeBasisPoints).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as web3 from "@solana/web3.js"; | |
import bs58 from "bs58"; | |
////////////////////////////////////////////////// | |
function readBytes(buf: Buffer, offset: number, length: number): Buffer { | |
const end = offset + length; | |
if (buf.byteLength < end) throw new RangeError("range out of bounds"); | |
return buf.subarray(offset, end); | |
} | |
function readBigUintLE(buf: Buffer, offset: number, length: number): bigint { | |
switch (length) { | |
case 1: return BigInt(buf.readUint8(offset)); | |
case 2: return BigInt(buf.readUint16LE(offset)); | |
case 4: return BigInt(buf.readUint32LE(offset)); | |
case 8: return buf.readBigUint64LE(offset); | |
} | |
throw new Error(`unsupported data size (${length} bytes)`); | |
} | |
function readBoolean(buf: Buffer, offset: number, length: number): boolean { | |
const data = readBytes(buf, offset, length); | |
for (const b of data) { | |
if (b) return true; | |
} | |
return false; | |
} | |
function readPublicKey(buf: Buffer, offset: number): web3.PublicKey { | |
return new web3.PublicKey(readBytes(buf, offset, web3.PUBLIC_KEY_LENGTH)); | |
} | |
////////////////////////////////////////////////// | |
const PUMP_PROGRAM_ID = new web3.PublicKey("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P"); | |
interface PumpGlobalState { | |
initialized: boolean | |
authority: web3.PublicKey | |
feeRecipient: web3.PublicKey | |
initialVirtualTokenReserves: bigint | |
initialVirtualSolReserves: bigint | |
initialRealTokenReserves: bigint | |
tokenTotalSupply: bigint | |
feeBasisPoints: bigint | |
} | |
// Calculated as the first 8 bytes of: `sha256("account:Global")`. | |
const PUMP_GLOBAL_STATE_SIGNATURE = Uint8Array.from([0xa7, 0xe8, 0xe8, 0xb1, 0xc8, 0x6c, 0x72, 0x7f]); | |
const PUMP_GLOBAL_STATE_SIZE = 0x69; | |
const PUMP_GLOBAL_STATE_OFFSETS = { | |
INITIALIZED: 0x08, | |
AUTHORITY: 0x09, | |
FEE_RECIPIENT: 0x29, | |
INITIAL_VIRTUAL_TOKEN_RESERVES: 0x49, | |
INITIAL_VIRTUAL_SOL_RESERVES: 0x51, | |
INITIAL_REAL_TOKEN_RESERVES: 0x59, | |
TOKEN_TOTAL_SUPPLY: 0x61, | |
FEE_BASIS_POINTS: 0x69, | |
}; | |
function decodePumpGlobalState(data: Buffer): PumpGlobalState { | |
const idlSignature = readBytes(data, 0, PUMP_GLOBAL_STATE_SIGNATURE.byteLength); | |
if (idlSignature.compare(PUMP_GLOBAL_STATE_SIGNATURE) !== 0) { | |
throw new Error("unexpected global state IDL signature"); | |
} | |
return { | |
initialized: readBoolean(data, PUMP_GLOBAL_STATE_OFFSETS.INITIALIZED, 1), | |
authority: readPublicKey(data, PUMP_GLOBAL_STATE_OFFSETS.AUTHORITY), | |
feeRecipient: readPublicKey(data, PUMP_GLOBAL_STATE_OFFSETS.FEE_RECIPIENT), | |
initialVirtualTokenReserves: readBigUintLE(data, PUMP_GLOBAL_STATE_OFFSETS.INITIAL_VIRTUAL_TOKEN_RESERVES, 8), | |
initialVirtualSolReserves: readBigUintLE(data, PUMP_GLOBAL_STATE_OFFSETS.INITIAL_VIRTUAL_SOL_RESERVES, 8), | |
initialRealTokenReserves: readBigUintLE(data, PUMP_GLOBAL_STATE_OFFSETS.INITIAL_REAL_TOKEN_RESERVES, 8), | |
tokenTotalSupply: readBigUintLE(data, PUMP_GLOBAL_STATE_OFFSETS.TOKEN_TOTAL_SUPPLY, 8), | |
feeBasisPoints: readBigUintLE(data, PUMP_GLOBAL_STATE_OFFSETS.FEE_BASIS_POINTS, 8), | |
}; | |
} | |
////////////////////////////////////////////////// | |
(async (rpcUrl: string) => { | |
const conn = new web3.Connection(rpcUrl, "confirmed"); | |
conn.onProgramAccountChange(PUMP_PROGRAM_ID, (info: web3.KeyedAccountInfo, ctx: web3.Context) => { | |
let state: PumpGlobalState | null = null; | |
try { | |
state = decodePumpGlobalState(info.accountInfo.data); | |
} catch (e) {} | |
if (!state) return null; | |
console.log(ctx.slot, "|", info.accountId.toBase58()); | |
console.dir(state); | |
console.log(); | |
}, undefined, [ | |
{ dataSize: PUMP_GLOBAL_STATE_SIGNATURE.byteLength + PUMP_GLOBAL_STATE_SIZE }, | |
{ memcmp: { offset: 0, bytes: bs58.encode(PUMP_GLOBAL_STATE_SIGNATURE) } }, | |
]); | |
// | |
// --- OUTPUT --- | |
// | |
// 273403135 | 4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf | |
// { | |
// initialized: true, | |
// authority: PublicKey [PublicKey(DCpJReAfonSrgohiQbTmKKbjbqVofspFRHz9yQikzooP)] { | |
// _bn: BN { negative: 0, words: [Array], length: 10, red: null } | |
// }, | |
// feeRecipient: PublicKey [PublicKey(CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM)] { | |
// _bn: BN { negative: 0, words: [Array], length: 10, red: null } | |
// }, | |
// initialVirtualTokenReserves: 1073000000000000n, | |
// initialVirtualSolReserves: 30000000000n, | |
// initialRealTokenReserves: 793100000000000n, | |
// tokenTotalSupply: 1000000000000000n, | |
// feeBasisPoints: 100n | |
// } | |
// | |
// -------------- | |
// | |
})(process.env.SOL_RPC_URL || "https://mainnet.helius-rpc.com/?api-key=00000000-0000-0000-0000-000000000000"); |
so cool @rubpy would you mind telling me how you know that?
I randomly tried lots of numbers yesterday.
{
initialized: true,
authority: PublicKey [PublicKey(FFWtrEQ4B4PKQoVuHYzZq8FabGkVatYzDpEVHsK5rrhF)] {
_bn: BN { negative: 0, words: [Array], length: 10, red: null }
},
feeRecipient: PublicKey [PublicKey(62qc2CNXwrYqQScmEdiZFFAnJR262PxWEuNQtxfafNgV)] {
_bn: BN { negative: 0, words: [Array], length: 10, red: null }
},
initialVirtualTokenReserves: 1073000000000000n,
initialVirtualSolReserves: 30000000000n,
initialRealTokenReserves: 793100000000000n,
tokenTotalSupply: 1000000000000000n,
feeBasisPoints: 100n,
withdrawAuthority: PublicKey [PublicKey(39azUYFWPz3VHgKCf3VChUwbpURdCHRxjWVowf5jUJjg)] {
_bn: BN { negative: 0, words: [Array], length: 10, red: null }
},
enableMigrate: false,
poolMigrationFee: 15000001n,
creatorFee: 0n,
feeRecipients: [
PublicKey [PublicKey(7VtfL8fvgNfhz17qKRMjzQEXgbdpnHHHQRh54R9jP2RJ)] {
_bn: [BN]
},
PublicKey [PublicKey(7hTckgnGnLQR6sdH7YkqFTAA7VwTfYFaZ6EhEsU3saCX)] {
_bn: [BN]
},
PublicKey [PublicKey(9rPYyANsfQZw3DnDmKE3YCQF5E8oD89UXoHn9JFEhJUz)] {
_bn: [BN]
},
PublicKey [PublicKey(AVmoTthdrX6tKt4nDjco2D775W2YK3sDhxPcMmzUAmTY)] {
_bn: [BN]
},
PublicKey [PublicKey(CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM)] {
_bn: [BN]
},
PublicKey [PublicKey(FWsW1xNtWscwNmKv6wVsU1iTzRN6wmmk3MjxRP5tT7hz)] {
_bn: [BN]
},
PublicKey [PublicKey(G5UZAVbAf46s7cKWoyKu8kYTip9DGTpbLZ2qa9Aq69dP)] {
_bn: [BN]
}
]
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@nshen
113
used to be the correctdataSize
, but as it stands, you're right (dataSize
is now512
).Recently, they've been making some changes to the Pump.fun program.
For the sake of completeness, here's the updated structure: