2025-11-20 17:56:45 +08:00
|
|
|
package pump_parser
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"log"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/gagliardetto/solana-go"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func checkBonkGmgnBuy(rawTx *RawTx) bool {
|
|
|
|
|
|
|
|
|
|
// 检查交易版本
|
|
|
|
|
var version, _ = rawTx.Version.(solana.MessageVersion)
|
|
|
|
|
if version != solana.MessageVersionLegacy {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查交易指令数量
|
|
|
|
|
if len(rawTx.Transaction.Message.Instructions) != 10 && len(rawTx.Transaction.Message.Instructions) != 9 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
accountList := rawTx.getAccountList()
|
|
|
|
|
// 检查 cu limit
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[0]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.ComputeBudget {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) != 1 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accountId := accountList[instruction.Accounts[0]].String()
|
|
|
|
|
if !strings.HasPrefix(accountId, "jitodontfront1111111111151111111111111655") {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 cu price
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[1]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.ComputeBudget {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 ata.createIdempotent
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[2]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SPLAssociatedTokenAccountProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "2" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) < 4 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// gmgn 会先创建 wsol 账户, 而不是 token 账户
|
|
|
|
|
accountId := accountList[instruction.Accounts[3]]
|
|
|
|
|
if accountId != solana.WrappedSol {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[3]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 token.syncNative
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[4]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.TokenProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "J" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset := 5
|
|
|
|
|
if len(rawTx.Transaction.Message.Instructions) == 10 {
|
|
|
|
|
// 检查 ata.create
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[offset]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SPLAssociatedTokenAccountProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "1" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 bonk.buy
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[offset]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != raydiumLaunchLabProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset++
|
|
|
|
|
|
|
|
|
|
// 检查 token.closeAccount
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[offset]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.TokenProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "A" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset++
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[offset]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset++
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[offset]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
axiomTxLoopupTable = solana.MustPublicKeyFromBase58("7RKtfATWCe98ChuwecNq8XCzAzfoK3DtZTprFsPMGtio")
|
2026-02-02 14:13:00 +08:00
|
|
|
axiomProgramID = solana.MustPublicKeyFromBase58("AxiomfHaWDemCFBLBayqnEnNwE6b7B2Qz3UmzMpgbMG6")
|
|
|
|
|
gmgnProgramID = solana.MustPublicKeyFromBase58("GMgnVFR8Jb39LoXsEVzb3DvBy3ywCmdmJquHUy1Lrkqb")
|
2025-11-20 17:56:45 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func checkBonkAxiomBuy(rawTx *RawTx) bool {
|
|
|
|
|
|
|
|
|
|
// 检查交易版本
|
|
|
|
|
var version, _ = rawTx.Version.(solana.MessageVersion)
|
|
|
|
|
if version == solana.MessageVersionLegacy || len(rawTx.Transaction.Message.AddressTableLookups) != 1 {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid transaction version or address table lookups: %v %v %v", rawTx.Transaction.Signatures[0].String(), version, len(rawTx.Transaction.Message.AddressTableLookups))
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 addressLookupTable 是否是 Axiom 的
|
|
|
|
|
if rawTx.Transaction.Message.AddressTableLookups[0].AccountKey != axiomTxLoopupTable {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid address lookup table: %v", rawTx.Transaction.Signatures[0].String())
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查交易指令数量
|
|
|
|
|
if len(rawTx.Transaction.Message.Instructions) != 10 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
accountList := rawTx.getAccountList()
|
|
|
|
|
// 检查 cu limit
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[0]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.ComputeBudget {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for ComputeBudget: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) != 1 {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid number of accounts for ComputeBudget: %v", len(instruction.Accounts))
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accountId := accountList[instruction.Accounts[0]].String()
|
|
|
|
|
if !strings.HasPrefix(accountId, "jitodontfront") || !strings.HasSuffix(accountId, "TradeWithAxiomDotTrade") {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid account ID for ComputeBudget: %v", accountId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 cu price
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[1]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.ComputeBudget {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for ComputeBudget: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 ata.createIdempotent
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[2]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SPLAssociatedTokenAccountProgramID {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for SPLAssociatedTokenAccount: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "2" {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid data for SPLAssociatedTokenAccount: %v", instruction.Data.String())
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) < 4 {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid number of accounts for SPLAssociatedTokenAccount: %v", len(instruction.Accounts))
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// axiom 会先创建 token 账户, 而不是 wsol 账户
|
|
|
|
|
accountId := accountList[instruction.Accounts[3]]
|
|
|
|
|
if accountId == solana.WrappedSol {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid account ID for SPLAssociatedTokenAccount, expected token account but got wsol: %v", accountId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 ata.createIdempotent
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[3]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SPLAssociatedTokenAccountProgramID {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for SPLAssociatedTokenAccount2: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "2" {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid data for SPLAssociatedTokenAccount2: %v", instruction.Data.String())
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) < 4 {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid number of accounts for SPLAssociatedTokenAccount2: %v", len(instruction.Accounts))
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// axiom 会先创建 token 账户, 而不是 wsol 账户
|
|
|
|
|
accountId := accountList[instruction.Accounts[3]]
|
|
|
|
|
if accountId != solana.WrappedSol {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid account ID for SPLAssociatedTokenAccount2, expected wsol but got: %v", accountId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[4]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for SystemProgram3: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid data for SystemProgram transfer3: %v", instruction.Data)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 token.syncNative
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[5]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.TokenProgramID {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for TokenProgram3: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "J" {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid data for TokenProgram syncNative3: %v", instruction.Data.String())
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 bonk.buy
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[6]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != raydiumLaunchLabProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 token.closeAccount
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[7]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.TokenProgramID {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for TokenProgram closeAccount: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "A" {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid data for TokenProgram closeAccount: %v", instruction.Data.String())
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[8]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for SystemProgram transfer4: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid data for SystemProgram transfer4: %v", instruction.Data)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[9]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid program ID for SystemProgram transfer5: %v", programId)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
log.Printf("CheckBonkAxiomBuy: Invalid data for SystemProgram transfer5: %v", instruction.Data)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
2026-02-02 14:13:00 +08:00
|
|
|
|
|
|
|
|
func checkPumpFunAxiomBuy(rawTx *RawTx) bool {
|
|
|
|
|
|
|
|
|
|
// 检查交易版本
|
|
|
|
|
if rawTx.Version == "legacy" || len(rawTx.Transaction.Message.AddressTableLookups) != 1 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 addressLookupTable 是否是 Axiom 的
|
|
|
|
|
if rawTx.Transaction.Message.AddressTableLookups[0].AccountKey != axiomTxLoopupTable {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查交易指令数量
|
|
|
|
|
if len(rawTx.Transaction.Message.Instructions) != 6 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accountList := rawTx.getAccountList()
|
|
|
|
|
// 检查 cu limit
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[0]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.ComputeBudget {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) != 1 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accountId := accountList[instruction.Accounts[0]].String()
|
|
|
|
|
if !strings.HasPrefix(accountId, "jitodontfront") || !strings.HasSuffix(accountId, "TradeWithAxiomDotTrade") {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 cu price
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[1]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.ComputeBudget {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 ata.createIdempotent
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[2]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SPLAssociatedTokenAccountProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "2" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) < 4 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// axiom 会先创建 token 账户, 而不是 wsol 账户
|
|
|
|
|
accountId := accountList[instruction.Accounts[3]]
|
|
|
|
|
if accountId == solana.WrappedSol {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查调用axiom合约
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[3]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != axiomProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[4]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[5]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func checkPumpFunGmgnBuy(rawTx *RawTx) bool {
|
|
|
|
|
|
|
|
|
|
// 检查交易版本
|
|
|
|
|
if rawTx.Version != "legacy" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查交易指令数量
|
|
|
|
|
if len(rawTx.Transaction.Message.Instructions) != 6 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accountList := rawTx.getAccountList()
|
|
|
|
|
// 检查 cu limit
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[0]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.ComputeBudget {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) != 1 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accountId := accountList[instruction.Accounts[0]].String()
|
|
|
|
|
if !strings.HasPrefix(accountId, "jitodontfront1111111111151111111111111655") {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 cu price
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[1]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.ComputeBudget {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 ata.createIdempotent
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[2]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SPLAssociatedTokenAccountProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if instruction.Data.String() != "2" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Accounts) < 4 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accountId := accountList[instruction.Accounts[3]]
|
|
|
|
|
if accountId == solana.WrappedSol {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查调用 gmgn 合约
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[3]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != gmgnProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[4]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查 transfer
|
|
|
|
|
{
|
|
|
|
|
instruction := rawTx.Transaction.Message.Instructions[5]
|
|
|
|
|
programId := accountList[instruction.ProgramIDIndex]
|
|
|
|
|
if programId != solana.SystemProgramID {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(instruction.Data) == 0 || instruction.Data[0] != 2 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|