292 lines
8.6 KiB
Go
292 lines
8.6 KiB
Go
package shreder
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"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)
|
|
txChannel := make(chan TxSignal, 1)
|
|
go func() {
|
|
ParseTransaction(
|
|
getTransaction(t, client, "5Gz1fa4Qhb35bkg9QCMXpxCX5uuNr7WcjcmrwajGZA7kXsvNS9pDnYe12ggWeSqf1nwZbVPob6DkX6fcwbE9ofBR"),
|
|
nil, txChannel,
|
|
false,
|
|
)
|
|
}()
|
|
|
|
signal := <-txChannel
|
|
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)
|
|
txChannel := make(chan TxSignal, 1)
|
|
go func() {
|
|
ParseTransaction(
|
|
getTransaction(t, client, "3gHF3TA2aA8rpjdmoEs2vA89vrq9J9NnTTUSXHfE6uXcaYP9cJgLtEUjCmsK9EWAyHEg7cEiepehQf4GFv1272jW"),
|
|
nil, txChannel,
|
|
false,
|
|
)
|
|
}()
|
|
|
|
signal := <-txChannel
|
|
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)
|
|
txChannel := make(chan TxSignal, 1)
|
|
go func() {
|
|
ParseTransaction(
|
|
getTransaction(t, client, "3XNi6b3j69SSStqLLRQVH5BNGVfEoFxGCzmpdd5FvrY4kmC8T644WGdEhCH9fAdrxWuR2Mtzgywq8K7qetu5MGyb"),
|
|
nil, txChannel,
|
|
false,
|
|
)
|
|
}()
|
|
|
|
signal := <-txChannel
|
|
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)
|
|
txChannel := make(chan TxSignal, 1)
|
|
go func() {
|
|
ParseTransaction(
|
|
getTransaction(t, client, "4DCEcXAWBxagXoUNGhWsJ7qfxq5SuE5BG2cBDBqAY7sCHkBopaMJu33ZnXnFHqzPMmWxVxq6666KRF4hMHVB33Ux"),
|
|
nil, txChannel,
|
|
false,
|
|
)
|
|
}()
|
|
|
|
signal := <-txChannel
|
|
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)
|
|
}
|
|
}
|