2026-01-07 13:16:22 +08:00
|
|
|
package shreder
|
|
|
|
|
|
|
|
|
|
import (
|
2026-01-08 15:20:50 +08:00
|
|
|
"context"
|
2026-01-07 13:16:22 +08:00
|
|
|
"encoding/hex"
|
2026-01-08 15:20:50 +08:00
|
|
|
"os"
|
2026-01-07 13:16:22 +08:00
|
|
|
"testing"
|
|
|
|
|
|
2026-01-08 15:20:50 +08:00
|
|
|
"github.com/gagliardetto/solana-go"
|
|
|
|
|
"github.com/gagliardetto/solana-go/rpc"
|
2026-01-07 13:16:22 +08:00
|
|
|
"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)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-08 15:20:50 +08:00
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 16:07:57 +08:00
|
|
|
func getTransaction(t *testing.T, client *rpc.Client, signature string) *SubscribeUpdateTransaction {
|
2026-01-08 15:20:50 +08:00
|
|
|
version := uint64(0)
|
|
|
|
|
tx, err := client.GetTransaction(
|
|
|
|
|
context.Background(),
|
2026-01-08 16:07:57 +08:00
|
|
|
solana.MustSignatureFromBase58(signature),
|
2026-01-08 15:20:50 +08:00
|
|
|
&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)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 16:07:57 +08:00
|
|
|
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)
|
2026-01-28 14:11:34 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "5Gz1fa4Qhb35bkg9QCMXpxCX5uuNr7WcjcmrwajGZA7kXsvNS9pDnYe12ggWeSqf1nwZbVPob6DkX6fcwbE9ofBR"),
|
|
|
|
|
nil,
|
|
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
2026-03-23 14:45:55 +08:00
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
2026-01-28 14:11:34 +08:00
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
2026-01-08 15:20:50 +08:00
|
|
|
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)
|
|
|
|
|
}
|
2026-01-08 16:20:17 +08:00
|
|
|
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)
|
|
|
|
|
}
|
2026-01-08 15:20:50 +08:00
|
|
|
}
|
2026-01-08 16:07:57 +08:00
|
|
|
|
|
|
|
|
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)
|
2026-01-28 14:11:34 +08:00
|
|
|
|
|
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "3gHF3TA2aA8rpjdmoEs2vA89vrq9J9NnTTUSXHfE6uXcaYP9cJgLtEUjCmsK9EWAyHEg7cEiepehQf4GFv1272jW"),
|
|
|
|
|
nil,
|
|
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
2026-03-23 14:45:55 +08:00
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
2026-01-28 14:11:34 +08:00
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 16:07:57 +08:00
|
|
|
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)
|
2026-01-28 14:11:34 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "3XNi6b3j69SSStqLLRQVH5BNGVfEoFxGCzmpdd5FvrY4kmC8T644WGdEhCH9fAdrxWuR2Mtzgywq8K7qetu5MGyb"),
|
|
|
|
|
nil,
|
|
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
2026-03-23 14:45:55 +08:00
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
2026-01-28 14:11:34 +08:00
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 16:07:57 +08:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-08 16:25:34 +08:00
|
|
|
|
|
|
|
|
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)
|
2026-01-28 14:11:34 +08:00
|
|
|
|
|
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "4DCEcXAWBxagXoUNGhWsJ7qfxq5SuE5BG2cBDBqAY7sCHkBopaMJu33ZnXnFHqzPMmWxVxq6666KRF4hMHVB33Ux"),
|
|
|
|
|
nil,
|
|
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
2026-03-23 14:45:55 +08:00
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
2026-01-28 14:11:34 +08:00
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 16:25:34 +08:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-22 17:10:13 +08:00
|
|
|
|
|
|
|
|
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)
|
2026-01-28 14:11:34 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "4QF5whXwjx234fMXeH3HrJCy5knFJmKPtgbXys8xKGz1pZypqPvXBr4BoAqXfYn8jLL4HXPY1pcvxCCW1XREFNxd"),
|
|
|
|
|
nil,
|
|
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
2026-03-23 14:45:55 +08:00
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
2026-01-28 14:11:34 +08:00
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-22 17:10:13 +08:00
|
|
|
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)
|
2026-01-28 14:11:34 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "yCnE7ZA8dqB5iAZtwpSN2ar5HXh3gBjgaG2xtnwXDPFyHAm5XFU8642uTZTH5A2iPQ6G9hrj5eEPAJiWrfe38gM"),
|
|
|
|
|
nil,
|
|
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
2026-03-23 14:45:55 +08:00
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
2026-01-28 14:11:34 +08:00
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
2026-01-22 17:10:13 +08:00
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-23 14:45:55 +08:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}()
|
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-23 14:52:27 +08:00
|
|
|
|
|
|
|
|
func TestParseRaydiumLaunchLabBuyExactOut(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, "4x2gArQAezap4RZKK5Tpfu1SNadCsTbjeUYG5KNggoHeGFiZdV1MmrrvXLXvyh2e6C1Gh22ohU4dFAzGw18y6VLT"),
|
|
|
|
|
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 != "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 != "nya666pQkP3PzWxi7JngU3rRMHuc7zbLK8c8wxQ4qpT" {
|
|
|
|
|
t.Fatalf("expected maker nya666pQkP3PzWxi7JngU3rRMHuc7zbLK8c8wxQ4qpT, got %s", signal.Maker)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0Address != "8ZTAvKJiPqExQYTYXoE2FuCoRFJAmyuEXXb4GbPvbonk" {
|
|
|
|
|
t.Fatalf("expected token0 address 8ZTAvKJiPqExQYTYXoE2FuCoRFJAmyuEXXb4GbPvbonk, got %s", signal.Token0Address)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0AmountUint64 != 2888057167672 {
|
|
|
|
|
t.Fatalf("expected token0 amount 2888057167672, got %d", signal.Token0AmountUint64)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token1AmountUint64 != 159300000 {
|
|
|
|
|
t.Fatalf("expected token1 amount 159300000, got %d", signal.Token1AmountUint64)
|
|
|
|
|
}
|
|
|
|
|
if signal.ExactSOL {
|
|
|
|
|
t.Fatalf("expected ExactSOL false, got true")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseRaydiumLaunchLabSellExactIn(t *testing.T) {
|
|
|
|
|
rpcUrl := os.Getenv("SOL_RPC_URL")
|
|
|
|
|
if rpcUrl == "" {
|
|
|
|
|
t.Fatalf("SOL_RPC_URL is not set")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client := rpc.New(rpcUrl)
|
2026-03-23 16:14:19 +08:00
|
|
|
loader := manuallyLoadAddressTable(t, client, solana.MustPublicKeyFromBase58("4xBW5fcrR1eityayfv6mrxC7zfQNy89YpqoVmqiTbfRh"))
|
2026-03-23 14:52:27 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "37LGuUiTnBpagELdwVWtffkbJaLsucbRimnFueKS23EaFdYsjHC42SS3XjyC5tyRaokj5tdwiKYfBqNFAmMbTUgv"),
|
2026-03-23 16:14:19 +08:00
|
|
|
loader,
|
2026-03-23 14:52:27 +08:00
|
|
|
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 != "raydiumlaunchlab" {
|
|
|
|
|
t.Fatalf("expected raydiumlaunchlab signal, got %s", signal.Label)
|
|
|
|
|
}
|
|
|
|
|
if signal.Event != "sell" {
|
|
|
|
|
t.Fatalf("expected sell event, got %s", signal.Event)
|
|
|
|
|
}
|
|
|
|
|
if signal.Maker != "7GSDLZHBNnEgYwe8TLLy8iDbnKWaR5NfNVoxvQJ26nux" {
|
|
|
|
|
t.Fatalf("expected maker 7GSDLZHBNnEgYwe8TLLy8iDbnKWaR5NfNVoxvQJ26nux, got %s", signal.Maker)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0Address != "6bs2ECcL1XG5Tw8t3xvpyCsQDunQpdYtDXNyD74bonk" {
|
|
|
|
|
t.Fatalf("expected token0 address 6bs2ECcL1XG5Tw8t3xvpyCsQDunQpdYtDXNyD74bonk, got %s", signal.Token0Address)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0AmountUint64 != 3144872514758 {
|
|
|
|
|
t.Fatalf("expected token0 amount 3144872514758, got %d", signal.Token0AmountUint64)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token1AmountUint64 != 373068521 {
|
|
|
|
|
t.Fatalf("expected token1 amount 373068521, got %d", signal.Token1AmountUint64)
|
|
|
|
|
}
|
|
|
|
|
if signal.ExactSOL {
|
|
|
|
|
t.Fatalf("expected ExactSOL false, got true")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseRaydiumLaunchLabSellExactOut(t *testing.T) {
|
|
|
|
|
rpcUrl := os.Getenv("SOL_RPC_URL")
|
|
|
|
|
if rpcUrl == "" {
|
|
|
|
|
t.Fatalf("SOL_RPC_URL is not set")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client := rpc.New(rpcUrl)
|
2026-03-23 16:14:19 +08:00
|
|
|
loader := manuallyLoadAddressTable(t, client, solana.MustPublicKeyFromBase58("DSaHkhDp17UexbZsg2VUnWjEuTwKNCJrnG4LW122ANfd"))
|
2026-03-23 14:52:27 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "3z8iC9zDLeQzjcLtUnwDT1j9Z5p5rFWXyCcRUhvUCVDTrPJSoZbbULkMTZk2mUUeAX1qaMBZUsPCd59B4KaGooSk"),
|
2026-03-23 16:14:19 +08:00
|
|
|
loader,
|
2026-03-23 14:52:27 +08:00
|
|
|
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 != "raydiumlaunchlab" {
|
|
|
|
|
t.Fatalf("expected raydiumlaunchlab signal, got %s", signal.Label)
|
|
|
|
|
}
|
|
|
|
|
if signal.Event != "sell" {
|
|
|
|
|
t.Fatalf("expected sell event, got %s", signal.Event)
|
|
|
|
|
}
|
|
|
|
|
if signal.Maker != "F4RMpjLMJZKmrYBxjpVadty7e326XUziLkYTDtNtpo2e" {
|
|
|
|
|
t.Fatalf("expected maker F4RMpjLMJZKmrYBxjpVadty7e326XUziLkYTDtNtpo2e, got %s", signal.Maker)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0Address != "ByubRkVymfNBoX9DUfUL39Zi6qzqWkTbLviQtx9ktxWv" {
|
|
|
|
|
t.Fatalf("expected token0 address ByubRkVymfNBoX9DUfUL39Zi6qzqWkTbLviQtx9ktxWv, got %s", signal.Token0Address)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0AmountUint64 != 594669717336 {
|
|
|
|
|
t.Fatalf("expected token0 amount 594669717336, got %d", signal.Token0AmountUint64)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token1AmountUint64 != 141400000 {
|
|
|
|
|
t.Fatalf("expected token1 amount 141400000, got %d", signal.Token1AmountUint64)
|
|
|
|
|
}
|
|
|
|
|
if !signal.ExactSOL {
|
|
|
|
|
t.Fatalf("expected ExactSOL true, got false")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-23 15:02:58 +08:00
|
|
|
|
|
|
|
|
func TestParseRaydiumLaunchLabCreate(t *testing.T) {
|
|
|
|
|
rpcUrl := os.Getenv("SOL_RPC_URL")
|
|
|
|
|
if rpcUrl == "" {
|
|
|
|
|
t.Fatalf("SOL_RPC_URL is not set")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client := rpc.New(rpcUrl)
|
2026-03-23 16:14:19 +08:00
|
|
|
loader := manuallyLoadAddressTable(t, client, solana.MustPublicKeyFromBase58("J7aYNVkReYKUSEvS79sg2YubtMQMxUetByAFrNw7qZ3G"))
|
2026-03-23 15:02:58 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "2qi4STgj33b1DydMKvtpqeSVwkcTJHww8ViX9ADMu2TaRz2uSGcVjgDyd9AELnn2N1ojSGy2qnM6uiXJc2vEcLmw"),
|
2026-03-23 16:14:19 +08:00
|
|
|
loader,
|
2026-03-23 15:02:58 +08:00
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
|
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
|
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(signals) == 0 {
|
|
|
|
|
t.Fatalf("expected at least 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 != "create" {
|
|
|
|
|
t.Fatalf("expected create event, got %s", signal.Event)
|
|
|
|
|
}
|
|
|
|
|
if signal.Maker != "F9TNxWymThfvs4kVVmyaBqx8pjxpvP7kScNBqiczeY84" {
|
|
|
|
|
t.Fatalf("expected maker F9TNxWymThfvs4kVVmyaBqx8pjxpvP7kScNBqiczeY84, got %s", signal.Maker)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0Address != "5VvwdKsYUjPTNbEotwDcV48PQEfi42of7TzaLyaybonk" {
|
|
|
|
|
t.Fatalf("expected token0 address 5VvwdKsYUjPTNbEotwDcV48PQEfi42of7TzaLyaybonk, got %s", signal.Token0Address)
|
|
|
|
|
}
|
|
|
|
|
if signal.IsToken2022 {
|
|
|
|
|
t.Fatalf("expected IsToken2022 false, got true")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParseRaydiumLaunchLabCreate2(t *testing.T) {
|
|
|
|
|
rpcUrl := os.Getenv("SOL_RPC_URL")
|
|
|
|
|
if rpcUrl == "" {
|
|
|
|
|
t.Fatalf("SOL_RPC_URL is not set")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client := rpc.New(rpcUrl)
|
2026-03-23 16:14:19 +08:00
|
|
|
loader := manuallyLoadAddressTable(t, client, solana.MustPublicKeyFromBase58("5Sq6FRoQkRbupnZM1iq9AFeLaSZPbVHgPheVqHD4GzVr"))
|
2026-03-23 15:02:58 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "3ZofgvJ3vrNRnyGfAFwENSrDAHxVuXhqrL4svwctHuxZHnAengj5SHeEwPJiJFPXYaBcnfrUAk2V4368LVVSEP2W"),
|
2026-03-23 16:14:19 +08:00
|
|
|
loader,
|
2026-03-23 15:02:58 +08:00
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
|
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
|
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(signals) == 0 {
|
|
|
|
|
t.Fatalf("expected at least 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 != "create" {
|
|
|
|
|
t.Fatalf("expected create event, got %s", signal.Event)
|
|
|
|
|
}
|
|
|
|
|
if signal.Maker != "7GhWwhaMgbKiRWxF93Bud6HnHMci6NCLTJyTxG8zFH51" {
|
|
|
|
|
t.Fatalf("expected maker 7GhWwhaMgbKiRWxF93Bud6HnHMci6NCLTJyTxG8zFH51, got %s", signal.Maker)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0Address != "GWeFeDVD75PVGHdLf7HrYJe2BYTiA8J3nVJXSqb4CpoU" {
|
|
|
|
|
t.Fatalf("expected token0 address GWeFeDVD75PVGHdLf7HrYJe2BYTiA8J3nVJXSqb4CpoU, got %s", signal.Token0Address)
|
|
|
|
|
}
|
|
|
|
|
if !signal.IsToken2022 {
|
|
|
|
|
t.Fatalf("expected IsToken2022 true, got false")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-23 15:43:08 +08:00
|
|
|
|
|
|
|
|
func manuallyLoadAddressTable(t *testing.T, client *rpc.Client, tablePubkey solana.PublicKey) *AddressTables {
|
|
|
|
|
loader := NewAddressTables(client, false)
|
|
|
|
|
table, err := loader.loadAddressTable(tablePubkey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to load address table: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loader.tables.Add(tablePubkey, &TableInfo{
|
|
|
|
|
addresses: table,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return loader
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParsePumpCreate(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("AXVvmhWaaPtV52jqYuTNqp1xRrkbxhfJfeHQKxq5cbvZ"))
|
|
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "3vUAHpBUoxeoZheo9m3XmufNUWmJWRAN4xZjSqDos71GL6tCKSTmJV6YeMS5XdVAbRAfqQi1rPusjbmEhoam4x9Y"),
|
|
|
|
|
loader,
|
|
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
|
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
|
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(signals) == 0 {
|
|
|
|
|
t.Fatalf("expected at least 1 signal, got %d", len(signals))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signal := signals[0]
|
|
|
|
|
if signal.Label != "pump" {
|
|
|
|
|
t.Fatalf("expected pump signal, got %s", signal.Label)
|
|
|
|
|
}
|
|
|
|
|
if signal.Event != "create" {
|
|
|
|
|
t.Fatalf("expected create event, got %s", signal.Event)
|
|
|
|
|
}
|
|
|
|
|
if signal.Maker != "8oVJLE69qH1i5jotFABcCoaPS38DAyZ7djRg6uuD3Cb7" {
|
|
|
|
|
t.Fatalf("expected maker 8oVJLE69qH1i5jotFABcCoaPS38DAyZ7djRg6uuD3Cb7, got %s", signal.Maker)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0Address != "AtaWsdyfcANLsHNdpYJyFdNvwSQnUzvhRN2MCCP9pump" {
|
|
|
|
|
t.Fatalf("expected token0 address AtaWsdyfcANLsHNdpYJyFdNvwSQnUzvhRN2MCCP9pump, got %s", signal.Token0Address)
|
|
|
|
|
}
|
|
|
|
|
if !signal.IsToken2022 {
|
|
|
|
|
t.Fatalf("expected IsToken2022 true, got false")
|
|
|
|
|
}
|
|
|
|
|
if signal.IsCashbackEnabled {
|
|
|
|
|
t.Fatalf("expected IsCashbackEnabled true, got false")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestParsePumpCreate2(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, "3EKKjtNFzhtQaA9GyPt5UJHLr5mWT2XodaxWoenUrcaPpN8BKm84ATVapdUJcb9sJVFyS4iKD9spGBKfqkSFutea"),
|
|
|
|
|
nil,
|
|
|
|
|
ch,
|
|
|
|
|
closed,
|
|
|
|
|
)
|
|
|
|
|
}()
|
|
|
|
|
go func() {
|
|
|
|
|
<-closed
|
|
|
|
|
close(ch)
|
|
|
|
|
}()
|
|
|
|
|
signals := make([]TxSignal, 0)
|
|
|
|
|
for signal := range ch {
|
|
|
|
|
signals = append(signals, signal)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(signals) == 0 {
|
|
|
|
|
t.Fatalf("expected at least 1 signal, got %d", len(signals))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signal := signals[0]
|
|
|
|
|
if signal.Label != "pump" {
|
|
|
|
|
t.Fatalf("expected pump signal, got %s", signal.Label)
|
|
|
|
|
}
|
|
|
|
|
if signal.Event != "create" {
|
|
|
|
|
t.Fatalf("expected create event, got %s", signal.Event)
|
|
|
|
|
}
|
|
|
|
|
if signal.Maker != "5mGqXMqUbJzxQ9aqbBttB4JUfAMqceSTmrtpt6RuPXdC" {
|
|
|
|
|
t.Fatalf("expected maker 5mGqXMqUbJzxQ9aqbBttB4JUfAMqceSTmrtpt6RuPXdC, got %s", signal.Maker)
|
|
|
|
|
}
|
|
|
|
|
if signal.Token0Address != "J9Hqi5VddcTNJ2F5EyxSZxC2JpJeymfJXjLhsCVPZpna" {
|
|
|
|
|
t.Fatalf("expected token0 address J9Hqi5VddcTNJ2F5EyxSZxC2JpJeymfJXjLhsCVPZpna, got %s", signal.Token0Address)
|
|
|
|
|
}
|
|
|
|
|
if !signal.IsToken2022 {
|
|
|
|
|
t.Fatalf("expected IsToken2022 true, got false")
|
|
|
|
|
}
|
|
|
|
|
if signal.IsCashbackEnabled {
|
|
|
|
|
t.Fatalf("expected IsCashbackEnabled true, got false")
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-23 16:01:41 +08:00
|
|
|
|
|
|
|
|
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)
|
2026-03-23 16:14:19 +08:00
|
|
|
loader := manuallyLoadAddressTable(t, client, solana.MustPublicKeyFromBase58("7RKtfATWCe98ChuwecNq8XCzAzfoK3DtZTprFsPMGtio"))
|
2026-03-23 16:01:41 +08:00
|
|
|
ch := make(chan TxSignal)
|
|
|
|
|
closed := make(chan struct{})
|
|
|
|
|
go func() {
|
|
|
|
|
ParseTransactionForSubscribe(
|
|
|
|
|
context.Background(),
|
|
|
|
|
getTransaction(t, client, "2v3qLsnrJ5KqUDqtzXyc3S9vT6cLvXbaVR6vwfhp4ufC4Sg1vmR5xMdxzrtvErq8kiC8g7d5wLAbEMe8NwXJE5MS"),
|
2026-03-23 16:14:19 +08:00
|
|
|
loader,
|
2026-03-23 16:01:41 +08:00
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
}
|