This commit is contained in:
thloyi
2026-02-02 14:13:00 +08:00
parent c25c856a47
commit 0eb1628119
3 changed files with 269 additions and 9 deletions

View File

@@ -173,6 +173,8 @@ func checkBonkGmgnBuy(rawTx *RawTx) bool {
var (
axiomTxLoopupTable = solana.MustPublicKeyFromBase58("7RKtfATWCe98ChuwecNq8XCzAzfoK3DtZTprFsPMGtio")
axiomProgramID = solana.MustPublicKeyFromBase58("AxiomfHaWDemCFBLBayqnEnNwE6b7B2Qz3UmzMpgbMG6")
gmgnProgramID = solana.MustPublicKeyFromBase58("GMgnVFR8Jb39LoXsEVzb3DvBy3ywCmdmJquHUy1Lrkqb")
)
func checkBonkAxiomBuy(rawTx *RawTx) bool {
@@ -366,3 +368,209 @@ func checkBonkAxiomBuy(rawTx *RawTx) bool {
return true
}
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
}

View File

@@ -61,6 +61,13 @@ func (tx *Tx) Parser() error {
return errors.New("rawTx is nil")
}
accountList := tx.rawTx.getAccountList()
if tx.rawTx.Meta.Err == nil {
for _, acc := range tx.rawTx.Transaction.Message.Instructions {
if accountList[acc.ProgramIDIndex] == solana.VoteProgramID {
tx.Vote = true
}
}
}
tx.TxHash = (*[64]byte)((tx.rawTx.Transaction.Signatures[0][:]))
tx.Signer = tx.rawTx.GetSigner()

63
tx.go
View File

@@ -65,6 +65,7 @@ type SolTransfer struct {
type Tx struct {
rawTx *RawTx
Vote bool
Signer solana.PublicKey
Err interface{} `json:"err,omitempty"`
Swaps []Swap `json:"swaps,omitempty"`
@@ -91,6 +92,10 @@ type Tx struct {
// todo pool info ??
}
func (tx *Tx) GetRawTx() *RawTx {
return tx.rawTx
}
func (tx *Tx) SetRawTx(t *RawTx) {
tx.rawTx = t
}
@@ -136,16 +141,33 @@ func (tx *Tx) CheckPlatform(swap Swap) (string, decimal.Decimal) {
platformFee = info.PlatformFee
break
}
if swap.Event == "buy" && swap.Program == SolProgramRaydiumLaunchLabBonk {
for _, p := range tx.Platform {
switch p.Platform {
case PlatformAxiom:
if !checkBonkAxiomBuy(rawTx) {
platform = PlatformFake
if swap.Event == "buy" {
switch swap.Program {
case SolProgramRaydiumLaunchLabBonk:
for _, p := range tx.Platform {
switch p.Platform {
case PlatformAxiom:
if !checkBonkAxiomBuy(rawTx) {
platform = PlatformFake
}
case PlatformGMGN:
if !checkBonkGmgnBuy(rawTx) {
platform = PlatformFake
}
}
case PlatformGMGN:
if !checkBonkGmgnBuy(rawTx) {
platform = PlatformFake
}
}
if swap.Program == SolProgramRaydiumLaunchLabBonk {
for _, p := range tx.Platform {
switch p.Platform {
case PlatformAxiom:
if !checkPumpFunAxiomBuy(rawTx) {
platform = PlatformFake
}
case PlatformGMGN:
if !checkPumpFunGmgnBuy(rawTx) {
platform = PlatformFake
}
}
}
}
@@ -196,6 +218,29 @@ func (s Swap) CheckEntryContract() string {
return EntryContractUnknown
}
func (tx *Tx) LoadAfterSOLBalance(swap Swap) decimal.Decimal {
if swap.User.Equals(tx.Signer) {
return tx.AfterSOLBalance
}
found := false
makerIndex := 0
for i, account := range tx.rawTx.getAccountList() {
if account == swap.User {
found = true
makerIndex = i
break
}
}
if found && makerIndex < len(tx.rawTx.Meta.PostBalances) {
return decimal.NewFromInt(
int64(tx.rawTx.Meta.PostBalances[makerIndex]),
).Div(decimal.NewFromInt(1000000000)) // sol decimals
}
return decimal.Zero
}
func (s Swap) CheckEntryContractV2() string {
name, ok := entryContractAddresses[s.EntryContract]
if ok {