Skip to content

Commit 0005209

Browse files
committed
added pumpfun bonds and new token scripts
1 parent da54a96 commit 0005209

4 files changed

Lines changed: 443 additions & 1 deletion

File tree

docker_postgres_db/grpc/grpc-requests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,4 @@ export async function createSubscribeWalletsPumpSwapTrades(listOfWallets: string
206206
entry: {},
207207
};
208208
return request;
209-
}
209+
}
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
import {
2+
CommitmentLevel,
3+
SubscribeRequest,
4+
} from "@triton-one/yellowstone-grpc";
5+
import pino from "pino";
6+
import Client from "@triton-one/yellowstone-grpc";
7+
import { PublicKey,VersionedTransactionResponse } from "@solana/web3.js";
8+
// import { buy, solanaConnection, sell } from "../transaction/transaction";
9+
import * as borsh from "@coral-xyz/borsh";
10+
import bs58 from "bs58";
11+
import base58 from "bs58";
12+
import { Buffer } from "buffer";
13+
import { struct, bool, u64, Layout } from "@coral-xyz/borsh";
14+
import { Idl } from "@project-serum/anchor";
15+
import {SolanaParser} from "@shyft-to/solana-transaction-parser";
16+
import { TOKEN_PROGRAM_ID, AccountLayout } from "@solana/spl-token";
17+
import {TransactionFormatter, SolanaEventParser, bnLayoutFormatter, transactionOutput, sell, buy} from "../../src/pumpfunsdk/pumpdotfun-sdk/src";
18+
import {createSubscribeNewPumpfunBondsTxRequest} from "./grpc-requests";
19+
import {token_db} from "../constants";
20+
import {handleSubscribe} from "./utils";
21+
let tokenSoldCount = {};
22+
let tokenRugCheckCount = {};
23+
let tokensHas40percentFreshWallet:any = {};
24+
const PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
25+
export const GLOBAL_ACCOUNT_SEED = "global";
26+
export const MINT_AUTHORITY_SEED = "mint-authority";
27+
export const BONDING_CURVE_SEED = "bonding-curve";
28+
const global_opeator = "jito";
29+
const client:any = new Client(
30+
GRPC_URL,
31+
GRPC_XTOKEN,
32+
{
33+
"grpc.max_receive_message_length": 64 * 1024 * 1024, // 64MiB
34+
}
35+
); //grpc endpoint
36+
const TXN_FORMATTER = new TransactionFormatter();
37+
const PUMP_FUN_PROGRAM_ID = new PublicKey(
38+
PROGRAM_ID
39+
);
40+
const PUMP_FUN_IX_PARSER = new SolanaParser([]);
41+
PUMP_FUN_IX_PARSER.addParserFromIdl(
42+
PUMP_FUN_PROGRAM_ID.toBase58(),
43+
pumpFunIdl as Idl,
44+
);
45+
const PUMP_FUN_EVENT_PARSER = new SolanaEventParser([], console);
46+
PUMP_FUN_EVENT_PARSER.addParserFromIdl(
47+
PUMP_FUN_PROGRAM_ID.toBase58(),
48+
pumpFunIdl as Idl,
49+
);
50+
51+
async function PingWhenTimeout(){
52+
//const currentSlot = await connection.getSlot("finalized");
53+
const pingNumber = await client.ping(1);
54+
//logger.info(`Ping number in price checker bot: ${pingNumber}`);
55+
if(pingNumber!==1) throw new Error("the grpc server has not response, restart the stream");
56+
57+
}
58+
59+
60+
async function getBondingCurveAccount(
61+
mint: PublicKey
62+
) {
63+
const tokenAccount = await connection.getAccountInfo(
64+
getBondingCurvePDA(mint),
65+
{
66+
commitment: "processed",
67+
}
68+
);
69+
if (!tokenAccount) {
70+
return null;
71+
}
72+
return BondingCurveAccount.fromBuffer(tokenAccount!.data);
73+
}
74+
function getBondingCurvePDA(mint: PublicKey) {
75+
return PublicKey.findProgramAddressSync(
76+
[Buffer.from(BONDING_CURVE_SEED), mint.toBuffer()],
77+
new PublicKey(PROGRAM_ID)
78+
)[0];
79+
}
80+
function decodePumpFunTxn(tx: any) {
81+
82+
if(tx.meta === undefined) return;
83+
if (tx.meta?.err) return;
84+
85+
const paredIxs = PUMP_FUN_IX_PARSER.parseTransactionData(
86+
tx.transaction.message,
87+
tx.meta.loadedAddresses,
88+
);
89+
90+
const pumpFunIxs = paredIxs.filter((ix) =>
91+
ix.programId.equals(PUMP_FUN_PROGRAM_ID),
92+
);
93+
94+
if (pumpFunIxs.length === 0) return;
95+
const events = PUMP_FUN_EVENT_PARSER.parseEvent(tx);
96+
const result = { instructions: pumpFunIxs, events };
97+
bnLayoutFormatter(result);
98+
return result;
99+
}
100+
export const structure = struct([
101+
u64("discriminator"),
102+
u64("virtualTokenReserves"),
103+
u64("virtualSolReserves"),
104+
u64("realTokenReserves"),
105+
u64("realSolReserves"),
106+
u64("tokenTotalSupply"),
107+
bool("complete"),
108+
]);
109+
110+
111+
export function decodeTransact(data){
112+
const output = base58.encode(Buffer.from(data,'base64'))
113+
return output;
114+
}
115+
116+
export function bondingCurveData(buffer: Buffer) {
117+
118+
let value = structure.decode(buffer);
119+
const discriminator = BigInt(value.discriminator);
120+
const virtualTokenReserves = BigInt(value.virtualTokenReserves);
121+
const virtualSolReserves = BigInt(value.virtualSolReserves);
122+
const realTokenReserves = BigInt(value.realTokenReserves);
123+
const realSolReserves = BigInt(value.realSolReserves);
124+
const tokenTotalSupply = BigInt(value.tokenTotalSupply);
125+
const complete = value.complete;
126+
return {
127+
discriminator,
128+
virtualTokenReserves,
129+
virtualSolReserves,
130+
realTokenReserves,
131+
realSolReserves,
132+
tokenTotalSupply,
133+
complete
134+
};
135+
}
136+
137+
async function retriveCurveState(bonding_curve: string) {
138+
try {
139+
const filters = [
140+
{
141+
dataSize: 165, //size of account (bytes)
142+
},
143+
{
144+
memcmp: {
145+
offset: 32, //location of our query in the account (bytes)
146+
bytes: bonding_curve, //our search criteria, a base58 encoded string
147+
},
148+
},
149+
];
150+
const accounts = await connection.getParsedProgramAccounts(
151+
TOKEN_PROGRAM_ID, //new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
152+
{ filters: filters }
153+
);
154+
let results: any = {};
155+
const solBalance = await connection.getBalance(
156+
new PublicKey(bonding_curve)
157+
);
158+
accounts.forEach((account, i) => {
159+
//Parse the account data
160+
const parsedAccountInfo: any = account.account.data;
161+
const mintAddress = parsedAccountInfo["parsed"]["info"]["mint"];
162+
const tokenBalance =
163+
parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
164+
165+
results[mintAddress] = tokenBalance;
166+
results["SOL"] = solBalance / 10 ** 9;
167+
});
168+
return results;
169+
} catch (e) {
170+
console.log(e);
171+
}
172+
}
173+
export async function tOutPut(data:any) {
174+
// Ensure data is defined and contains the necessary properties
175+
if (!data || !data.account || !data.account.account) {
176+
// throw new Error("Invalid data format");
177+
return;
178+
}
179+
180+
181+
const dataTx = data.account.account;
182+
183+
// Safely decode each piece of transaction data
184+
const signature = dataTx.txnSignature ? decodeTransact(dataTx.txnSignature) : null;
185+
const pubKey:any = dataTx.pubkey ? decodeTransact(dataTx.pubkey) : null;
186+
const owner = dataTx.owner ? decodeTransact(dataTx.owner) : null;
187+
let poolstate:any = null;
188+
if(signature !== null){
189+
console.log("signature: ", signature);
190+
console.log("pubKey: ", pubKey);
191+
console.log("owner: ", owner)
192+
193+
let targetToken = '';
194+
195+
const curve_state = await retriveCurveState(pubKey);
196+
const accList = Object.keys(curve_state);
197+
console.log(accList);
198+
for(const token of accList){
199+
if(token !== "SOL") targetToken = token;
200+
}
201+
console.log(targetToken);
202+
try {
203+
poolstate = bondingCurveData(dataTx.data);
204+
console.log(poolstate);
205+
if(poolstate.complete === true){
206+
//token_db.insertNewGrad(targetToken, 0);
207+
}
208+
} catch (error) {
209+
console.error("Failed to decode pool state:", error);
210+
}
211+
}
212+
213+
return {
214+
signature,
215+
pubKey,
216+
owner,
217+
poolstate
218+
};
219+
}
220+
221+
setInterval(PingWhenTimeout, 1000);
222+
223+
224+
/**
225+
* Subscribes to a new pumpfun bonds and insert it to db
226+
*/
227+
export async function streamAnyNewBonds() {
228+
229+
const stream = await client.subscribe();
230+
const r1: SubscribeRequest = await createSubscribeNewPumpfunBondsTxRequest();
231+
handleSubscribe(stream, r1);
232+
stream.on("data", (data:any) => {
233+
try{
234+
tOutPut(data);
235+
}catch(err){
236+
console.log(err)
237+
}
238+
239+
});
240+
241+
242+
243+
}
244+
245+
streamAnyNewBonds();
246+
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import {
2+
CommitmentLevel,
3+
SubscribeRequest,
4+
} from "@triton-one/yellowstone-grpc";
5+
import pino from "pino";
6+
import base58 from "bs58";
7+
import Client from "@triton-one/yellowstone-grpc";
8+
import { PublicKey } from "@solana/web3.js";
9+
import * as borsh from "@coral-xyz/borsh";
10+
import bs58 from "bs58";
11+
import { Buffer } from "buffer";
12+
import { Idl } from "@project-serum/anchor";
13+
import {SolanaParser} from "@shyft-to/solana-transaction-parser";
14+
import {TransactionFormatter, SolanaEventParser, bnLayoutFormatter, transactionOutput, buy, sell,launchTransactionOutput1, snipe} from "../../src/pumpfunsdk/pumpdotfun-sdk/src";
15+
import pumpFunIdl from "../../src/pumpfunsdk/pumpdotfun-sdk/src/IDL/pump-fun.json";
16+
import {createSubscribeNewPumpfunTokenRequest } from "./grpc-requests"
17+
import {handleSubscribe} from "./utils";
18+
import {data_db} from "./constants";
19+
//import {master_db } from "../master-wallet-checker/constants";
20+
// import {checkIfFreshWallet} from "../master-wallet-checker/rugCheck";
21+
const PROGRAM_ID = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
22+
23+
const client:any = new Client(
24+
GRPC_URL,
25+
GRPC_XTOKEN,
26+
{
27+
"grpc.max_receive_message_length": 64 * 1024 * 1024, // 64MiB
28+
}
29+
); //grpc endpoint
30+
const TXN_FORMATTER = new TransactionFormatter();
31+
const PUMP_FUN_PROGRAM_ID = new PublicKey(
32+
PROGRAM_ID
33+
);
34+
const PUMP_FUN_IX_PARSER = new SolanaParser([]);
35+
PUMP_FUN_IX_PARSER.addParserFromIdl(
36+
PUMP_FUN_PROGRAM_ID.toBase58(),
37+
pumpFunIdl as Idl,
38+
);
39+
const PUMP_FUN_EVENT_PARSER = new SolanaEventParser([], console);
40+
PUMP_FUN_EVENT_PARSER.addParserFromIdl(
41+
PUMP_FUN_PROGRAM_ID.toBase58(),
42+
pumpFunIdl as Idl,
43+
);
44+
function decodePumpFunTxn(tx: any) {
45+
46+
if(tx.meta === undefined) return;
47+
if (tx.meta?.err) return;
48+
49+
const paredIxs = PUMP_FUN_IX_PARSER.parseTransactionData(
50+
tx.transaction.message,
51+
tx.meta.loadedAddresses,
52+
);
53+
54+
const pumpFunIxs = paredIxs.filter((ix) =>
55+
ix.programId.equals(PUMP_FUN_PROGRAM_ID),
56+
);
57+
58+
if (pumpFunIxs.length === 0) return;
59+
const events = PUMP_FUN_EVENT_PARSER.parseEvent(tx);
60+
const result = { instructions: pumpFunIxs, events };
61+
bnLayoutFormatter(result);
62+
return result;
63+
}
64+
async function getLatestPriceInSOL(virtualSolReserves:number, virtualTokenReserves:number){
65+
const fixedTokenSupply = 1000000000;
66+
return (
67+
((fixedTokenSupply * virtualSolReserves) / virtualTokenReserves)/10**12
68+
);
69+
}
70+
71+
export async function checkLatestPrice(txout:any){
72+
if(txout === undefined) return { type: "", tokenAddress: "", user: "", tokenAmount: 0, solAmount: 0, latestPrice: 0, noOfBundledBuys: 0, isRug: false, devAddress: "" };
73+
const type = txout.type;
74+
const tokenAddress = txout.mint;
75+
const noOfBundledBuys = txout.noOfBundledBuys;
76+
const user = txout.user;
77+
const tokenAmount = txout.tokenAmount;
78+
const solAmount = txout.solAmount;
79+
const isRug = txout.isRug;
80+
const devAddress = txout.devAddress;
81+
const latestPrice = (await getLatestPriceInSOL(txout.virtualSolReserves, txout.virtualTokenReserves)).toFixed(11);
82+
83+
return { type, tokenAddress, user, tokenAmount, solAmount, latestPrice, noOfBundledBuys, isRug, devAddress };
84+
}
85+
86+
export async function checkBondingCurvePercentageAndPrice(data:any, txout:any, signature:string){
87+
const {type, tokenAddress, user, tokenAmount, solAmount, latestPrice, noOfBundledBuys, isRug, devAddress} = await checkLatestPrice(txout);
88+
89+
90+
91+
data_db.insertTokenRug(tokenAddress, 0);
92+
const tokenAmt = tokenAmount/10**6;
93+
const currentTimestamp = Date.now();
94+
let tokenName = "";
95+
96+
data_db.updateTokenName(tokenAddress, tokenName);
97+
data_db.insertLatestToken(tokenAddress, user, solAmount, 0, currentTimestamp, 0, Number(latestPrice), tokenAmt);
98+
data_db.insertPfLaunchTxn(tokenAddress, signature);
99+
100+
101+
}
102+
103+
/**
104+
* Subscribes to a new pumpfun token and insert it to db
105+
*/
106+
export async function streamAnyNewTokens() {
107+
const stream = await client.subscribe();
108+
const r1: SubscribeRequest = await createSubscribeNewPumpfunTokenRequest(undefined);
109+
handleSubscribe(stream, r1);
110+
stream.on("data", (data:any) => {
111+
if (data.transaction !== undefined) {
112+
const txn = TXN_FORMATTER.formTransactionFromJson(
113+
data.transaction,
114+
Date.now(),
115+
);
116+
let parsedTxn = decodePumpFunTxn(txn);
117+
if (!parsedTxn) return;
118+
const signature = base58.encode(data.transaction.transaction.signature);
119+
console.log("Signature: ", signature);
120+
const tOutput = launchTransactionOutput1(parsedTxn, {})
121+
//logger.info(`New token created: ${data.transaction.transaction.meta.postTokenBalances[0].mint}`);
122+
checkBondingCurvePercentageAndPrice(data, tOutput, signature);
123+
}
124+
});
125+
126+
}
127+
128+
streamAnyNewTokens();

0 commit comments

Comments
 (0)