Skip to content

Instantly share code, notes, and snippets.

@ducphamle2
Created November 25, 2024 02:28
Show Gist options
  • Select an option

  • Save ducphamle2/afe37ef4f82bb82b25597fc114cc646d to your computer and use it in GitHub Desktop.

Select an option

Save ducphamle2/afe37ef4f82bb82b25597fc114cc646d to your computer and use it in GitHub Desktop.
Subscribe to new agents.land tokens
import {
Connection,
Logs,
ParsedInnerInstruction,
ParsedInstruction,
ParsedTransactionWithMeta,
PartiallyDecodedInstruction,
PublicKey,
} from "@solana/web3.js";
import { Metaplex } from "@metaplex-foundation/js";
const PUMP_FUN_PROGRAM_ID = "wenBqrmxFAvovtz2jVRyNKjQQWzFF23Qv5oz3PSvDEW";
const seenTransactions: Array<string> = []; // The log listener is sometimes triggered multiple times for a single transaction, don't react to tranasctions we've already seen
export async function subscribeToNewPumpFunTokens(
connection: Connection,
callback: Function
) {
connection.onLogs(
new PublicKey(PUMP_FUN_PROGRAM_ID),
async (txLogs: Logs) => {
if (seenTransactions.includes(txLogs.signature)) {
return;
}
if (
!findLogEntry("Launch", txLogs.logs) &&
!findLogEntry("Swap", txLogs.logs)
) {
return; // If "InitializeMint2" is not in log entries then it's not pump.fun launch transaction
}
seenTransactions.push(txLogs.signature);
// handle Launch case
// need 5 fields: creator, mint address, name, uri, and date
try {
const data = await fetchPumpFunLaunchInfo(connection, txLogs.signature); // With poolKeys you can do a swap
console.log("new pump fun token; ", data);
callback(data);
} catch (error) {
console.log("error fetching pump fun launch info: ", error);
}
}
);
// await connection.removeOnLogsListener(subId);
console.log("Listening to new Pump.fun tokens...");
}
function findLogEntry(
needle: string,
logEntries: Array<string>
): string | null {
for (let i = 0; i < logEntries.length; ++i) {
if (logEntries[i].includes(needle)) {
return logEntries[i];
}
}
return null;
}
async function fetchPumpFunLaunchInfo(
connection: Connection,
txSignature: string
): Promise<any> {
const tx = await connection.getParsedTransaction(txSignature, {
commitment: "confirmed",
});
if (!tx) {
console.error("Failed to fetch transaction with signature " + txSignature);
return;
}
return parseTokenLaunchInfo(connection, tx);
}
async function parseTokenLaunchInfo(connection: Connection, txData: ParsedTransactionWithMeta) {
const initInstruction = findInstructionByProgramId(
txData.transaction.message.instructions,
new PublicKey(PUMP_FUN_PROGRAM_ID)
) as PartiallyDecodedInstruction | null;
if (!initInstruction) {
throw new Error("Failed to find lp init instruction in lp init tx");
}
console.dir(txData.meta?.innerInstructions, { depth: null });
const creator = initInstruction.accounts[2];
const mintAddress = initInstruction.accounts[3];
const bondingCurve = initInstruction.accounts[4];
const metaplex = Metaplex.make(connection);
const token = await metaplex
.nfts()
.findByMint({ mintAddress: mintAddress }, { commitment: "confirmed" });
return {
creator,
mintAddress,
metadata: token,
bondingCurve,
};
}
function findInstructionByProgramId(
instructions: Array<ParsedInstruction | PartiallyDecodedInstruction>,
programId: PublicKey
): ParsedInstruction | PartiallyDecodedInstruction | null {
for (let i = 0; i < instructions.length; i++) {
if (instructions[i].programId.equals(programId)) {
return instructions[i];
}
}
return null;
}
@ducphamle2
Copy link
Copy Markdown
Author

the initInstruction.accounts[] follows the account order of the main agents.land Solana program, "Launch" instruction

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment