119 lines
3.1 KiB
Go
119 lines
3.1 KiB
Go
package shreder
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
"github.com/gagliardetto/solana-go"
|
|
)
|
|
|
|
var binanceWalletProgramID = solana.MustPublicKeyFromBase58("B3111yJCeHBcA1bizdJjUFPALfhAfSRnAbJzGUtnt56A")
|
|
|
|
const (
|
|
binanceWalletMinDataLen = 72
|
|
binanceWalletSolOffset = 23
|
|
binanceWalletTokenOff = 39
|
|
binanceWalletSolRepeat = 51
|
|
binanceWalletSideOff = 71
|
|
|
|
binanceWalletPumpBuy = 0x05
|
|
binanceWalletPumpSell = 0x06
|
|
)
|
|
|
|
var binanceWalletMarker = []byte{0x13, 0x2c, 0x82, 0x94, 0x48, 0x38, 0x2c, 0xee}
|
|
|
|
func parseBinanceWalletInstruction(tx VersionedTransaction, instructionIndex int) (TxSignalBatch, error) {
|
|
if instructionIndex >= len(tx.Instructions) {
|
|
return nil, fmt.Errorf("instruction index out of bounds")
|
|
}
|
|
|
|
instruction := tx.Instructions[instructionIndex]
|
|
if len(instruction.Data) < len(binanceWalletMarker) || !bytes.Contains(instruction.Data, binanceWalletMarker) {
|
|
return nil, nil
|
|
}
|
|
if len(instruction.Data) < binanceWalletMinDataLen {
|
|
return nil, fmt.Errorf("data too short for binance wallet, len=%d", len(instruction.Data))
|
|
}
|
|
|
|
side := instruction.Data[binanceWalletSideOff]
|
|
if side != binanceWalletPumpBuy && side != binanceWalletPumpSell {
|
|
return nil, nil
|
|
}
|
|
|
|
if len(instruction.Accounts) <= 8 {
|
|
return nil, fmt.Errorf("accounts too short")
|
|
}
|
|
|
|
wsolIdx := 7
|
|
tokenIdx := 8
|
|
if side == binanceWalletPumpSell {
|
|
wsolIdx = 8
|
|
tokenIdx = 7
|
|
}
|
|
|
|
wsolKey, err := tx.GetAccount(int(instruction.Accounts[wsolIdx]))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !wsolKey.Equals(solana.WrappedSol) {
|
|
return nil, nil
|
|
}
|
|
mint, err := tx.GetAccount(int(instruction.Accounts[tokenIdx]))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
amountA := binary.LittleEndian.Uint64(instruction.Data[binanceWalletSolOffset : binanceWalletSolOffset+8])
|
|
if amountA == 0 && len(instruction.Data) >= binanceWalletSolRepeat+8 {
|
|
repeat := binary.LittleEndian.Uint64(instruction.Data[binanceWalletSolRepeat : binanceWalletSolRepeat+8])
|
|
if repeat > 0 {
|
|
amountA = repeat
|
|
}
|
|
}
|
|
amountB := binary.LittleEndian.Uint64(instruction.Data[binanceWalletTokenOff : binanceWalletTokenOff+8])
|
|
|
|
solAmount := amountA
|
|
tokenAmount := amountB
|
|
if side == binanceWalletPumpSell {
|
|
solAmount = amountB
|
|
tokenAmount = amountA
|
|
}
|
|
|
|
maker := ""
|
|
if len(tx.StaticAccountKeys) > 0 {
|
|
maker = tx.StaticAccountKeys[0].String()
|
|
} else if len(instruction.Accounts) > 0 {
|
|
key, err := tx.GetAccount(int(instruction.Accounts[0]))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
maker = key.String()
|
|
}
|
|
|
|
event := "buy"
|
|
exactIn := true
|
|
if side == binanceWalletPumpSell {
|
|
event = "sell"
|
|
exactIn = false
|
|
}
|
|
|
|
return TxSignalBatch{&TxSignal{
|
|
TxHash: tx.Signatures[0].String(),
|
|
Label: "binancewallet",
|
|
Maker: maker,
|
|
Token0Address: mint.String(),
|
|
Token1Address: wsolMint,
|
|
Token0Amount: formatTokenAmount(tokenAmount),
|
|
Token1Amount: formatSolAmount(solAmount),
|
|
Program: "Pump",
|
|
Event: event,
|
|
IsToken2022: false,
|
|
IsMayhemMode: false,
|
|
ExactSOL: exactIn,
|
|
Block: tx.Block,
|
|
Token0AmountUint64: tokenAmount,
|
|
Token1AmountUint64: solAmount,
|
|
}}, nil
|
|
}
|