171 lines
4.8 KiB
Go
171 lines
4.8 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"log"
|
||
|
|
|
||
|
|
"github.com/gagliardetto/solana-go"
|
||
|
|
"github.com/gagliardetto/solana-go/programs/address-lookup-table"
|
||
|
|
"github.com/gagliardetto/solana-go/rpc"
|
||
|
|
|
||
|
|
"github.com/samlior/libsam/pkg/shreder"
|
||
|
|
)
|
||
|
|
|
||
|
|
// OKX tx
|
||
|
|
// const dlmmSignature = "4W8gD2iEYyvzpPiW9BhdH5hUrfXhqH46ziLzPkaaxmaA8XXK53erUvrPdZ5cY2XrgWwix1hmRajUnGAiNp4cSGpN"
|
||
|
|
|
||
|
|
const dlmmSignature = "3Kcm9rqG9mJ6PCM5DuUoZ6jk3kzbH7J5GP488E5MKMwodf2NXgddygEcWBmzRBrV2YZFmXtG22gvcJixqdsCjRPn"
|
||
|
|
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
const rpcURL = "https://staked.helius-rpc.com?api-key=5adcf1f9-5719-43d1-bf3f-c2d4e1e5f94d"
|
||
|
|
if rpcURL == "" {
|
||
|
|
log.Fatal("SOL_RPC_URL is not set")
|
||
|
|
}
|
||
|
|
|
||
|
|
client := rpc.New(rpcURL)
|
||
|
|
sig, err := solana.SignatureFromBase58(dlmmSignature)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalf("invalid dlmmSignature: %v", err)
|
||
|
|
}
|
||
|
|
version := uint64(0)
|
||
|
|
tx, err := client.GetTransaction(
|
||
|
|
context.Background(),
|
||
|
|
sig,
|
||
|
|
&rpc.GetTransactionOpts{
|
||
|
|
Commitment: rpc.CommitmentFinalized,
|
||
|
|
MaxSupportedTransactionVersion: &version,
|
||
|
|
},
|
||
|
|
)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalf("getTransaction failed: %v", err)
|
||
|
|
}
|
||
|
|
if tx == nil || tx.Transaction == nil {
|
||
|
|
log.Fatal("transaction is empty")
|
||
|
|
}
|
||
|
|
|
||
|
|
rawTx, err := tx.Transaction.GetTransaction()
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalf("decode transaction failed: %v", err)
|
||
|
|
}
|
||
|
|
if rawTx == nil {
|
||
|
|
log.Fatal("decoded transaction is nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(rawTx.Message.AddressTableLookups) > 0 {
|
||
|
|
tables := make(map[solana.PublicKey]solana.PublicKeySlice, len(rawTx.Message.AddressTableLookups))
|
||
|
|
for _, lookup := range rawTx.Message.AddressTableLookups {
|
||
|
|
state, err := addresslookuptable.GetAddressLookupTable(context.Background(), client, lookup.AccountKey)
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalf("load address table %s failed: %v", lookup.AccountKey, err)
|
||
|
|
}
|
||
|
|
tables[lookup.AccountKey] = state.Addresses
|
||
|
|
}
|
||
|
|
if err := rawTx.Message.SetAddressTables(tables); err != nil {
|
||
|
|
log.Fatalf("set address tables failed: %v", err)
|
||
|
|
}
|
||
|
|
if err := rawTx.Message.ResolveLookups(); err != nil {
|
||
|
|
log.Fatalf("resolve address lookups failed: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
update := toSubscribeUpdate(tx.Slot, rawTx)
|
||
|
|
signals := shreder.ParseTransaction(update, nil, true)
|
||
|
|
if len(signals) == 0 {
|
||
|
|
fmt.Println("no signals parsed")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
printed := false
|
||
|
|
for _, signal := range signals {
|
||
|
|
if signal == nil || signal.Label != "dlmm" {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
printed = true
|
||
|
|
output, err := json.MarshalIndent(signal, "", " ")
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalf("marshal signal failed: %v", err)
|
||
|
|
}
|
||
|
|
fmt.Println(string(output))
|
||
|
|
}
|
||
|
|
|
||
|
|
if printed {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
fmt.Println("no dlmm signal parsed, dump all signals:")
|
||
|
|
for _, signal := range signals {
|
||
|
|
if signal == nil {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
output, err := json.MarshalIndent(signal, "", " ")
|
||
|
|
if err != nil {
|
||
|
|
log.Fatalf("marshal signal failed: %v", err)
|
||
|
|
}
|
||
|
|
fmt.Println(string(output))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func toSubscribeUpdate(slot uint64, tx *solana.Transaction) *shreder.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([]*shreder.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] = &shreder.CompiledInstruction{
|
||
|
|
ProgramIdIndex: uint32(instr.ProgramIDIndex),
|
||
|
|
Accounts: accounts,
|
||
|
|
Data: instr.Data[:],
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
addressTableLookups := make([]*shreder.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] = &shreder.MessageAddressTableLookup{
|
||
|
|
AccountKey: lookup.AccountKey[:],
|
||
|
|
WritableIndexes: writable,
|
||
|
|
ReadonlyIndexes: readonly,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return &shreder.SubscribeUpdateTransaction{
|
||
|
|
Transaction: &shreder.Transaction{
|
||
|
|
Signatures: signatures,
|
||
|
|
Message: &shreder.Message{
|
||
|
|
Header: &shreder.MessageHeader{
|
||
|
|
NumRequiredSignatures: uint32(tx.Message.Header.NumRequiredSignatures),
|
||
|
|
NumReadonlySignedAccounts: uint32(tx.Message.Header.NumReadonlySignedAccounts),
|
||
|
|
NumReadonlyUnsignedAccounts: uint32(tx.Message.Header.NumReadonlyUnsignedAccounts),
|
||
|
|
},
|
||
|
|
AccountKeys: accountKeys,
|
||
|
|
RecentBlockhash: nil,
|
||
|
|
Instructions: instructions,
|
||
|
|
Versioned: false,
|
||
|
|
AddressTableLookups: addressTableLookups,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
Slot: slot,
|
||
|
|
}
|
||
|
|
}
|