Files
libsam/pkg/shreder/txparser_test.go

519 lines
14 KiB
Go

package shreder
import (
"context"
"encoding/hex"
"fmt"
"os"
"testing"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
"github.com/near/borsh-go"
)
func TestDecodeAxiomArgs(t *testing.T) {
tests := []struct {
name string
hexData string
}{
{
name: "pump amm sell Test 0",
hexData: "00686f08bb1b0000007eb4ac020000000001020200183c",
},
{
name: "pump amm buy Test 1",
hexData: "00c09ee6050000000001c94d882600000000020200323c",
},
{
name: "pump buy Test 2",
hexData: "00d8d3bc0000000000bb7c53f009000000000104185a",
},
{
name: "pump sell Test 3",
hexData: "009bbf69ec08080000830bc61200000000010103a000",
},
{
name: "pump swap sell Test 4",
hexData: "00c98ea7588b0000009adf3b010000000001020200283c",
},
{
name: "pump swap sell Test 5",
hexData: "00d3727f9301000000f9a50b0100000000010202001e00",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
data, err := hex.DecodeString(tt.hexData)
if err != nil {
t.Fatalf("failed to decode hex string: %v", err)
return
}
var args flasArgs
if err := borsh.Deserialize(&args, data[1:]); err != nil {
t.Fatalf("failed to decode Axiom args: %v", err)
return
}
t.Logf("Decoded Axiom Args: %+v", args)
})
}
}
func toUpdata(slot uint64, tx *solana.Transaction) *SubscribeUpdateTransaction {
signatures := make([][]byte, len(tx.Signatures))
for i, sig := range tx.Signatures {
signatures[i] = sig[:]
}
accountKeys := make([][]byte, len(tx.Message.AccountKeys))
for i, key := range tx.Message.AccountKeys {
accountKeys[i] = key[:]
}
instructions := make([]*CompiledInstruction, len(tx.Message.Instructions))
for i, instr := range tx.Message.Instructions {
accounts := make([]byte, len(instr.Accounts))
for j, acc := range instr.Accounts {
accounts[j] = byte(acc)
}
instructions[i] = &CompiledInstruction{
ProgramIdIndex: uint32(instr.ProgramIDIndex),
Accounts: accounts,
Data: instr.Data[:],
}
}
addressTableLookups := make([]*MessageAddressTableLookup, len(tx.Message.AddressTableLookups))
for i, lookup := range tx.Message.AddressTableLookups {
writable := make([]byte, len(lookup.WritableIndexes))
for j, idx := range lookup.WritableIndexes {
writable[j] = byte(idx)
}
readonly := make([]byte, len(lookup.ReadonlyIndexes))
for j, idx := range lookup.ReadonlyIndexes {
readonly[j] = byte(idx)
}
addressTableLookups[i] = &MessageAddressTableLookup{
AccountKey: lookup.AccountKey[:],
WritableIndexes: writable,
ReadonlyIndexes: readonly,
}
}
return &SubscribeUpdateTransaction{
Transaction: &Transaction{
Signatures: signatures,
Message: &Message{
Header: &MessageHeader{
NumRequiredSignatures: uint32(tx.Message.Header.NumRequiredSignatures),
NumReadonlySignedAccounts: uint32(tx.Message.Header.NumReadonlySignedAccounts),
NumReadonlyUnsignedAccounts: uint32(tx.Message.Header.NumReadonlyUnsignedAccounts),
},
AccountKeys: accountKeys,
RecentBlockhash: nil, // TODO
Instructions: instructions,
Versioned: false, // TODO
AddressTableLookups: addressTableLookups,
},
},
Slot: slot,
}
}
func getTransaction(t *testing.T, client *rpc.Client, signature string) *SubscribeUpdateTransaction {
version := uint64(0)
tx, err := client.GetTransaction(
context.Background(),
solana.MustSignatureFromBase58(signature),
&rpc.GetTransactionOpts{
Commitment: rpc.CommitmentFinalized,
MaxSupportedTransactionVersion: &version,
},
)
if err != nil {
t.Fatalf("failed to get transaction: %v", err)
}
_tx, err := tx.Transaction.GetTransaction()
if err != nil {
t.Fatalf("failed to get transaction: %v", err)
}
return toUpdata(tx.Slot, _tx)
}
func TestParseTermBuy(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, "5Gz1fa4Qhb35bkg9QCMXpxCX5uuNr7WcjcmrwajGZA7kXsvNS9pDnYe12ggWeSqf1nwZbVPob6DkX6fcwbE9ofBR"),
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 != "terminal" {
t.Fatalf("expected terminal signal, got %s", signal.Label)
}
if signal.Event != "buy" {
t.Fatalf("expected buy event, got %s", signal.Event)
}
if signal.Maker != "BaLxyjXzATAnfm7cc5AFhWBpiwnsb71THcnofDLTWAPK" {
t.Fatalf("expected maker BaLxyjXzATAnfm7cc5AFhWBpiwnsb71THcnofDLTWAPK, got %s", signal.Maker)
}
if signal.Token0Address != "5Wgv54peXRKDHYHapAELzgNKEPEh9E5Bf3hUR3sTpump" {
t.Fatalf("expected token0 address 5Wgv54peXRKDHYHapAELzgNKEPEh9E5Bf3hUR3sTpump, got %s", signal.Token0Address)
}
if signal.Token0AmountUint64 != 6952026214256 {
t.Fatalf("expected token0 amount 6952026214256, got %d", signal.Token0AmountUint64)
}
if signal.Token1AmountUint64 != 653333333 {
t.Fatalf("expected token1 amount 653333333, got %d", signal.Token1AmountUint64)
}
}
func TestParseBonkBuy(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, "3gHF3TA2aA8rpjdmoEs2vA89vrq9J9NnTTUSXHfE6uXcaYP9cJgLtEUjCmsK9EWAyHEg7cEiepehQf4GFv1272jW"),
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 != "bonk" {
t.Fatalf("expected bonk signal, got %s", signal.Label)
}
if signal.Event != "buy" {
t.Fatalf("expected buy event, got %s", signal.Event)
}
if signal.Maker != "BFobdhAbdBteBuDvHUdBthsQqJyMuWnG9SGUheW1Ni2C" {
t.Fatalf("expected maker BFobdhAbdBteBuDvHUdBthsQqJyMuWnG9SGUheW1Ni2C, got %s", signal.Maker)
}
if signal.Token0Address != "Awupo9Jxe1fsc7eEtCEcN9D3PoyReQhc9WEuEAHXpump" {
t.Fatalf("expected token0 address Awupo9Jxe1fsc7eEtCEcN9D3PoyReQhc9WEuEAHXpump, got %s", signal.Token0Address)
}
if signal.Token0AmountUint64 != 8616799656436 {
t.Fatalf("expected token0 amount 8616799656436, got %d", signal.Token0AmountUint64)
}
if signal.Token1AmountUint64 != 495000000 {
t.Fatalf("expected token1 amount 495000000, got %d", signal.Token1AmountUint64)
}
}
func TestParseBonkSell(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, "3XNi6b3j69SSStqLLRQVH5BNGVfEoFxGCzmpdd5FvrY4kmC8T644WGdEhCH9fAdrxWuR2Mtzgywq8K7qetu5MGyb"),
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 != "bonk" {
t.Fatalf("expected bonk signal, got %s", signal.Label)
}
if signal.Event != "sell" {
t.Fatalf("expected sell event, got %s", signal.Event)
}
if signal.Maker != "2xTT7XXCEYSCrRb3G4Egc4ZwpCe78qq6r7w6ChZhbTXc" {
t.Fatalf("expected maker 2xTT7XXCEYSCrRb3G4Egc4ZwpCe78qq6r7w6ChZhbTXc, got %s", signal.Maker)
}
if signal.Token0Address != "8pgpJDYuojYXvb8KE4Hv7DCty12FrkqpKChgfHzspump" {
t.Fatalf("expected token0 address 8pgpJDYuojYXvb8KE4Hv7DCty12FrkqpKChgfHzspump, got %s", signal.Token0Address)
}
if signal.Token0AmountUint64 != 6235736929390 {
t.Fatalf("expected token0 amount 6235736929390, got %d", signal.Token0AmountUint64)
}
if signal.Token1AmountUint64 != 1379707703 {
t.Fatalf("expected token1 amount 1379707703, got %d", signal.Token1AmountUint64)
}
}
func TestParsePhotonBuy(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, "4DCEcXAWBxagXoUNGhWsJ7qfxq5SuE5BG2cBDBqAY7sCHkBopaMJu33ZnXnFHqzPMmWxVxq6666KRF4hMHVB33Ux"),
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 != "photon" {
t.Fatalf("expected terminal signal, got %s", signal.Label)
}
if signal.Event != "buy" {
t.Fatalf("expected buy event, got %s", signal.Event)
}
if signal.Maker != "8sUm7sLf3Steu6oVyVQqoA9GpFcMRz6YhrAidd4x7g7a" {
t.Fatalf("expected maker 8sUm7sLf3Steu6oVyVQqoA9GpFcMRz6YhrAidd4x7g7a, got %s", signal.Maker)
}
if signal.Token0Address != "jx4PF2MwC7AK9S8dTeYm29hM3vAN8Rtfs2VX4Vz5UVj" {
t.Fatalf("expected token0 address jx4PF2MwC7AK9S8dTeYm29hM3vAN8Rtfs2VX4Vz5UVj, got %s", signal.Token0Address)
}
if signal.Token0AmountUint64 != 1796593710706 {
t.Fatalf("expected token0 amount 1796593710706, got %d", signal.Token0AmountUint64)
}
if signal.Token1AmountUint64 != 1955555553 {
t.Fatalf("expected token1 amount 1955555553, got %d", signal.Token1AmountUint64)
}
}
func TestParseJupiterV6PumpFunBuy(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, "4QF5whXwjx234fMXeH3HrJCy5knFJmKPtgbXys8xKGz1pZypqPvXBr4BoAqXfYn8jLL4HXPY1pcvxCCW1XREFNxd"),
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 != "jupiterv6" {
t.Fatalf("expected jupiterv6 signal, got %s", signal.Label)
}
if signal.Event != "buy" {
t.Fatalf("expected buy event, got %s", signal.Event)
}
if signal.Maker != "92ySgsZs3rsrUAq2aeEqYacXQQGmz6e4xHPrRGxLDJXb" {
t.Fatalf("expected maker 92ySgsZs3rsrUAq2aeEqYacXQQGmz6e4xHPrRGxLDJXb, got %s", signal.Maker)
}
if signal.Token0Address != "5kSWidFwDKPZiNf52TfincpVn8ufvkAfEzZ9pk8Dpump" {
t.Fatalf("expected token0 address 5kSWidFwDKPZiNf52TfincpVn8ufvkAfEzZ9pk8Dpump, got %s", signal.Token0Address)
}
if signal.Token0AmountUint64 != 2410530637576 {
t.Fatalf("expected token0 amount 2410530637576, got %d", signal.Token0AmountUint64)
}
if signal.Token1AmountUint64 != 380000000 {
t.Fatalf("expected token1 amount 380000000, got %d", signal.Token1AmountUint64)
}
if !signal.ExactSOL {
t.Fatalf("expected ExactSOL true, got false")
}
}
func TestParseJupiterV6PumpFunSell(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, "yCnE7ZA8dqB5iAZtwpSN2ar5HXh3gBjgaG2xtnwXDPFyHAm5XFU8642uTZTH5A2iPQ6G9hrj5eEPAJiWrfe38gM"),
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 != "jupiterv6" {
t.Fatalf("expected jupiterv6 signal, got %s", signal.Label)
}
if signal.Event != "sell" {
t.Fatalf("expected sell event, got %s", signal.Event)
}
if signal.Maker != "CGfWcKKcVQNBCL1vpxXdg6rvfYpQmnS3WkyA22Lk5XnZ" {
t.Fatalf("expected maker CGfWcKKcVQNBCL1vpxXdg6rvfYpQmnS3WkyA22Lk5XnZ, got %s", signal.Maker)
}
if signal.Token0Address != "wp8Mwxy7btAD9hNWsfJyoPNJnjXS9fuNG4mnhQZpump" {
t.Fatalf("expected token0 address wp8Mwxy7btAD9hNWsfJyoPNJnjXS9fuNG4mnhQZpump, got %s", signal.Token0Address)
}
if signal.Token0AmountUint64 != 127531720509990 {
t.Fatalf("expected token0 amount 127531720509990, got %d", signal.Token0AmountUint64)
}
if signal.Token1AmountUint64 != 5296451290 {
t.Fatalf("expected token1 amount 5296451290, got %d", signal.Token1AmountUint64)
}
if signal.ExactSOL {
t.Fatalf("expected ExactSOL false, got true")
}
}
func TestParseRaydiumLaunchLabBuyExactIn(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, "2erxUsE92LdrxhWy6HryUJpvBpVUociu2UY6AGoX7E6orrqm6AYxDzhmub3J9PDPa5CPNwWZBG8rCxKCdquVo2Lc"),
nil,
ch,
closed,
)
}()
go func() {
<-closed
close(ch)
}()
fmt.Println("Parsing Raydium Launch Lab Buy Exact In")
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 != "raydiumlaunchlab" {
t.Fatalf("expected raydiumlaunchlab signal, got %s", signal.Label)
}
if signal.Event != "buy" {
t.Fatalf("expected buy event, got %s", signal.Event)
}
if signal.Maker != "56JZV81H3XJedVWcV8RTXrn5YD6WW2k2LTGVDGCUwyYb" {
t.Fatalf("expected maker 56JZV81H3XJedVWcV8RTXrn5YD6WW2k2LTGVDGCUwyYb, got %s", signal.Maker)
}
if signal.Token0Address != "676zr3qFwy3XUXwVkQVdV9cidSaxcS6SrHga8cK4kKej" {
t.Fatalf("expected token0 address 676zr3qFwy3XUXwVkQVdV9cidSaxcS6SrHga8cK4kKej, got %s", signal.Token0Address)
}
if signal.Token0AmountUint64 != 15336821188103 {
t.Fatalf("expected token0 amount 15336821188103, got %d", signal.Token0AmountUint64)
}
if signal.Token1AmountUint64 != 1000000000 {
t.Fatalf("expected token1 amount 1000000000, got %d", signal.Token1AmountUint64)
}
if !signal.ExactSOL {
t.Fatalf("expected ExactSOL true, got false")
}
}