chore: suppot flas bonk buy/sell
This commit is contained in:
@@ -10,10 +10,12 @@ import (
|
|||||||
|
|
||||||
var flasProgramID = solana.MustPublicKeyFromBase58("FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9")
|
var flasProgramID = solana.MustPublicKeyFromBase58("FLASHX8DrLbgeR8FcfNV1F5krxYcYMUdBkrP1EPBtxB9")
|
||||||
var (
|
var (
|
||||||
flasBuyTokensIX = []byte{0x00, 0x1, 0x1b}
|
flasBuyTokensIX = []byte{0x00, 0x1, 0x1b}
|
||||||
flasSellTokensIX = []byte{0x01, 0x1, 0x1a}
|
flasSellTokensIX = []byte{0x01, 0x1, 0x1a}
|
||||||
flasAmmBuyTokensIX = []byte{0x00, 0x2, 0x2}
|
flasAmmBuyTokensIX = []byte{0x00, 0x2, 0x2}
|
||||||
flasAmmSellTokensIX = []byte{0x01, 0x2, 0x2}
|
flasAmmSellTokensIX = []byte{0x01, 0x2, 0x2}
|
||||||
|
flasBonkBuyTokensIX = []byte{0x00, 0x2, 0x7}
|
||||||
|
flasBonkSellTokensIX = []byte{0x01, 0x2, 0x7}
|
||||||
)
|
)
|
||||||
|
|
||||||
type flasArgs struct {
|
type flasArgs struct {
|
||||||
@@ -53,6 +55,10 @@ func parseFlasInstruction(tx VersionedTransaction, instructionIndex int) (TxSign
|
|||||||
txSignal, err = parseFlasAmmBuy(tx, instructionIndex)
|
txSignal, err = parseFlasAmmBuy(tx, instructionIndex)
|
||||||
} else if matchMethod(methodData, flasAmmSellTokensIX) {
|
} else if matchMethod(methodData, flasAmmSellTokensIX) {
|
||||||
txSignal, err = parseFlasAmmSell(tx, instructionIndex)
|
txSignal, err = parseFlasAmmSell(tx, instructionIndex)
|
||||||
|
} else if matchMethod(methodData, flasBonkBuyTokensIX) {
|
||||||
|
txSignal, err = parseFlasBonkBuy(tx, instructionIndex)
|
||||||
|
} else if matchMethod(methodData, flasBonkSellTokensIX) {
|
||||||
|
txSignal, err = parseFlasBonkSell(tx, instructionIndex)
|
||||||
}
|
}
|
||||||
if txSignal != nil {
|
if txSignal != nil {
|
||||||
return TxSignalBatch{txSignal}, err
|
return TxSignalBatch{txSignal}, err
|
||||||
@@ -216,3 +222,78 @@ func parseFlasBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, err
|
|||||||
Token1AmountUint64: args.Amount1,
|
Token1AmountUint64: args.Amount1,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseFlasBonkBuy(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) {
|
||||||
|
instruction := tx.Instructions[instructionIndex]
|
||||||
|
if len(instruction.Accounts) < 16 {
|
||||||
|
return nil, fmt.Errorf("accounts too short")
|
||||||
|
}
|
||||||
|
|
||||||
|
mint, err := tx.GetAccount(int(instruction.Accounts[15]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
user, err := tx.GetAccount(int(instruction.Accounts[1]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(instruction.Data) > 20 {
|
||||||
|
instruction.Data = instruction.Data[:20]
|
||||||
|
}
|
||||||
|
var args flasArgs
|
||||||
|
if err := borsh.Deserialize(&args, instruction.Data[1:]); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TxSignal{
|
||||||
|
TxHash: tx.Signatures[0].String(),
|
||||||
|
Label: "flas",
|
||||||
|
Maker: user.String(),
|
||||||
|
Token0Address: mint.String(),
|
||||||
|
Token1Address: wsolMint,
|
||||||
|
Token0Amount: formatTokenAmount(args.Amount2),
|
||||||
|
Token1Amount: formatSolAmount(args.Amount1),
|
||||||
|
Program: "RaydiumLaunchLab",
|
||||||
|
Event: "buy",
|
||||||
|
ExactSOL: true,
|
||||||
|
Block: tx.Block,
|
||||||
|
Token0AmountUint64: args.Amount2,
|
||||||
|
Token1AmountUint64: args.Amount1,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFlasBonkSell(tx VersionedTransaction, instructionIndex int) (*TxSignal, error) {
|
||||||
|
instruction := tx.Instructions[instructionIndex]
|
||||||
|
if len(instruction.Accounts) < 16 {
|
||||||
|
return nil, fmt.Errorf("accounts too short")
|
||||||
|
}
|
||||||
|
|
||||||
|
mint, err := tx.GetAccount(int(instruction.Accounts[15]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
user, err := tx.GetAccount(int(instruction.Accounts[1]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var args flasArgs
|
||||||
|
if err := borsh.Deserialize(&args, instruction.Data[1:]); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse buy tokens args: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TxSignal{
|
||||||
|
TxHash: tx.Signatures[0].String(),
|
||||||
|
Label: "flas",
|
||||||
|
Maker: user.String(),
|
||||||
|
Token0Address: mint.String(),
|
||||||
|
Token1Address: wsolMint,
|
||||||
|
Token0Amount: formatTokenAmount(args.Amount1),
|
||||||
|
Token1Amount: formatSolAmount(args.Amount2),
|
||||||
|
Program: "RaydiumLaunchLab",
|
||||||
|
Event: "sell",
|
||||||
|
Block: tx.Block,
|
||||||
|
Token0AmountUint64: args.Amount1,
|
||||||
|
Token1AmountUint64: args.Amount2,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -896,3 +896,114 @@ func TestParsePumpCreate2(t *testing.T) {
|
|||||||
t.Fatalf("expected IsCashbackEnabled true, got false")
|
t.Fatalf("expected IsCashbackEnabled true, got false")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseFlasBonkBuy(t *testing.T) {
|
||||||
|
rpcUrl := os.Getenv("SOL_RPC_URL")
|
||||||
|
if rpcUrl == "" {
|
||||||
|
t.Fatalf("SOL_RPC_URL is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := rpc.New(rpcUrl)
|
||||||
|
loader := manuallyLoadAddressTable(t, client, solana.MustPublicKeyFromBase58("7RKtfATWCe98ChuwecNq8XCzAzfoK3DtZTprFsPMGtio"))
|
||||||
|
ch := make(chan TxSignal)
|
||||||
|
closed := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
ParseTransactionForSubscribe(
|
||||||
|
context.Background(),
|
||||||
|
getTransaction(t, client, "5ED51fnabzxsPqjswp7R9qbfuTep7avtsQnsYg4R6w2jc9Ys2mMCXFNNnDNvUUhaREJS5Tz1dSfBL1dufXzDsiaX"),
|
||||||
|
loader,
|
||||||
|
ch,
|
||||||
|
closed,
|
||||||
|
)
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
<-closed
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
signals := make([]TxSignal, 0)
|
||||||
|
for signal := range ch {
|
||||||
|
signals = append(signals, signal)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(signals) != 1 {
|
||||||
|
t.Fatalf("expected 1 signal, got %d", len(signals))
|
||||||
|
}
|
||||||
|
|
||||||
|
signal := signals[0]
|
||||||
|
if signal.Label != "flas" {
|
||||||
|
t.Fatalf("expected flas signal, got %s", signal.Label)
|
||||||
|
}
|
||||||
|
if signal.Event != "buy" {
|
||||||
|
t.Fatalf("expected buy event, got %s", signal.Event)
|
||||||
|
}
|
||||||
|
if signal.Maker != "75KjigN4rgweGMRu5oWY4DBPELpQ1TYsBQAXuzs7hKVA" {
|
||||||
|
t.Fatalf("expected maker 75KjigN4rgweGMRu5oWY4DBPELpQ1TYsBQAXuzs7hKVA, got %s", signal.Maker)
|
||||||
|
}
|
||||||
|
if signal.Token0Address != "2aMTnF7Kz9aRhTMmiVuSwbQ9Msrdkgm4RvFoJfZPbonk" {
|
||||||
|
t.Fatalf("expected token0 address 2aMTnF7Kz9aRhTMmiVuSwbQ9Msrdkgm4RvFoJfZPbonk, got %s", signal.Token0Address)
|
||||||
|
}
|
||||||
|
if signal.Token0AmountUint64 != 1052495896871 {
|
||||||
|
t.Fatalf("expected token0 amount 1052495896871, got %d", signal.Token0AmountUint64)
|
||||||
|
}
|
||||||
|
if signal.Token1AmountUint64 != 99000000 {
|
||||||
|
t.Fatalf("expected token1 amount 99000000, got %d", signal.Token1AmountUint64)
|
||||||
|
}
|
||||||
|
if !signal.ExactSOL {
|
||||||
|
t.Fatalf("expected ExactSOL true, got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseFlasBonkSell(t *testing.T) {
|
||||||
|
rpcUrl := os.Getenv("SOL_RPC_URL")
|
||||||
|
if rpcUrl == "" {
|
||||||
|
t.Fatalf("SOL_RPC_URL is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
client := rpc.New(rpcUrl)
|
||||||
|
ch := make(chan TxSignal)
|
||||||
|
closed := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
ParseTransactionForSubscribe(
|
||||||
|
context.Background(),
|
||||||
|
getTransaction(t, client, "2v3qLsnrJ5KqUDqtzXyc3S9vT6cLvXbaVR6vwfhp4ufC4Sg1vmR5xMdxzrtvErq8kiC8g7d5wLAbEMe8NwXJE5MS"),
|
||||||
|
nil,
|
||||||
|
ch,
|
||||||
|
closed,
|
||||||
|
)
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
<-closed
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
signals := make([]TxSignal, 0)
|
||||||
|
for signal := range ch {
|
||||||
|
signals = append(signals, signal)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(signals) != 1 {
|
||||||
|
t.Fatalf("expected 1 signal, got %d", len(signals))
|
||||||
|
}
|
||||||
|
|
||||||
|
signal := signals[0]
|
||||||
|
if signal.Label != "flas" {
|
||||||
|
t.Fatalf("expected flas signal, got %s", signal.Label)
|
||||||
|
}
|
||||||
|
if signal.Event != "sell" {
|
||||||
|
t.Fatalf("expected sell event, got %s", signal.Event)
|
||||||
|
}
|
||||||
|
if signal.Maker != "7rtyqW2yr76Y9iCTvbAzkDdaJU8mbx3ZuzW9sTZ3pV2q" {
|
||||||
|
t.Fatalf("expected maker 7rtyqW2yr76Y9iCTvbAzkDdaJU8mbx3ZuzW9sTZ3pV2q, got %s", signal.Maker)
|
||||||
|
}
|
||||||
|
if signal.Token0Address != "2aMTnF7Kz9aRhTMmiVuSwbQ9Msrdkgm4RvFoJfZPbonk" {
|
||||||
|
t.Fatalf("expected token0 address 2aMTnF7Kz9aRhTMmiVuSwbQ9Msrdkgm4RvFoJfZPbonk, got %s", signal.Token0Address)
|
||||||
|
}
|
||||||
|
if signal.Token0AmountUint64 != 6413676607028 {
|
||||||
|
t.Fatalf("expected token0 amount 6413676607028, got %d", signal.Token0AmountUint64)
|
||||||
|
}
|
||||||
|
if signal.Token1AmountUint64 != 249361301 {
|
||||||
|
t.Fatalf("expected token1 amount 249361301, got %d", signal.Token1AmountUint64)
|
||||||
|
}
|
||||||
|
if signal.ExactSOL {
|
||||||
|
t.Fatalf("expected ExactSOL false, got true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user