chore: support pump create
This commit is contained in:
@@ -29,6 +29,15 @@ type pumpBuyArgs struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type pumpCreateCoinV2Args struct {
|
type pumpCreateCoinV2Args struct {
|
||||||
|
Name string
|
||||||
|
Symbol string
|
||||||
|
Uri string
|
||||||
|
Creator solana.PublicKey
|
||||||
|
IsMayhemMode bool
|
||||||
|
IsCashbackEnabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type legacyPumpCreateCoinV2Args struct {
|
||||||
Name string
|
Name string
|
||||||
Symbol string
|
Symbol string
|
||||||
Uri string
|
Uri string
|
||||||
@@ -37,7 +46,6 @@ type pumpCreateCoinV2Args struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parsePumpInstruction(msg VersionedTransaction, instructionIndex int) (TxSignalBatch, error) {
|
func parsePumpInstruction(msg VersionedTransaction, instructionIndex int) (TxSignalBatch, error) {
|
||||||
|
|
||||||
instruction := msg.Instructions[instructionIndex]
|
instruction := msg.Instructions[instructionIndex]
|
||||||
if len(instruction.Data) < 8 {
|
if len(instruction.Data) < 8 {
|
||||||
return nil, fmt.Errorf("data is empty")
|
return nil, fmt.Errorf("data is empty")
|
||||||
@@ -114,7 +122,18 @@ func parsePumpCreateV2(tx VersionedTransaction, instruction Instructions) (*TxSi
|
|||||||
|
|
||||||
var args pumpCreateCoinV2Args
|
var args pumpCreateCoinV2Args
|
||||||
if err := borsh.Deserialize(&args, instruction.Data[8:]); err != nil {
|
if err := borsh.Deserialize(&args, instruction.Data[8:]); err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse create coin v2 args: %w", err)
|
var legacyArgs legacyPumpCreateCoinV2Args
|
||||||
|
if err := borsh.Deserialize(&legacyArgs, instruction.Data[8:]); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse create coin v2 args: %w", err)
|
||||||
|
}
|
||||||
|
args = pumpCreateCoinV2Args{
|
||||||
|
Name: legacyArgs.Name,
|
||||||
|
Symbol: legacyArgs.Symbol,
|
||||||
|
Uri: legacyArgs.Uri,
|
||||||
|
Creator: legacyArgs.Creator,
|
||||||
|
IsMayhemMode: legacyArgs.IsMayhemMode,
|
||||||
|
IsCashbackEnabled: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &TxSignal{
|
return &TxSignal{
|
||||||
@@ -129,6 +148,7 @@ func parsePumpCreateV2(tx VersionedTransaction, instruction Instructions) (*TxSi
|
|||||||
Event: "create",
|
Event: "create",
|
||||||
IsToken2022: tokenProgramKey.String() != tokenProgram,
|
IsToken2022: tokenProgramKey.String() != tokenProgram,
|
||||||
IsMayhemMode: args.IsMayhemMode,
|
IsMayhemMode: args.IsMayhemMode,
|
||||||
|
IsCashbackEnabled: args.IsCashbackEnabled,
|
||||||
Block: tx.Block,
|
Block: tx.Block,
|
||||||
Token0AmountUint64: 0,
|
Token0AmountUint64: 0,
|
||||||
Token1AmountUint64: 0,
|
Token1AmountUint64: 0,
|
||||||
|
|||||||
@@ -28,27 +28,28 @@ func SetLogLevel(level slog.Level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TxSignal struct {
|
type TxSignal struct {
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
TxHash string `json:"tx_hash"`
|
TxHash string `json:"tx_hash"`
|
||||||
Maker string `json:"maker"`
|
Maker string `json:"maker"`
|
||||||
Token0Address string `json:"token0_address"`
|
Token0Address string `json:"token0_address"`
|
||||||
Token1Address string `json:"token1_address"`
|
Token1Address string `json:"token1_address"`
|
||||||
Token0Amount decimal.Decimal `json:"token0_amount"`
|
Token0Amount decimal.Decimal `json:"token0_amount"`
|
||||||
Token1Amount decimal.Decimal `json:"token1_amount"`
|
Token1Amount decimal.Decimal `json:"token1_amount"`
|
||||||
Block uint64 `json:"block"`
|
Block uint64 `json:"block"`
|
||||||
BlockAt time.Time `json:"block_at"`
|
BlockAt time.Time `json:"block_at"`
|
||||||
BlockIndex uint64 `json:"block_index"`
|
BlockIndex uint64 `json:"block_index"`
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
Program string `json:"program"`
|
Program string `json:"program"`
|
||||||
IsProcessed bool `json:"is_processed"`
|
IsProcessed bool `json:"is_processed"`
|
||||||
IsToken2022 bool `json:"is_token2022"`
|
IsToken2022 bool `json:"is_token2022"`
|
||||||
IsMayhemMode bool `json:"is_mayhem_mode"`
|
IsMayhemMode bool `json:"is_mayhem_mode"`
|
||||||
CUPrice decimal.Decimal `json:"cu_price"`
|
IsCashbackEnabled bool `json:"is_cashback_enabled"`
|
||||||
CULimit uint32 `json:"cu_limit"`
|
CUPrice decimal.Decimal `json:"cu_price"`
|
||||||
SWQoSAgent string `json:"swqos_agent"`
|
CULimit uint32 `json:"cu_limit"`
|
||||||
SWQoSTips decimal.Decimal `json:"swqos_tips"`
|
SWQoSAgent string `json:"swqos_agent"`
|
||||||
TableCnt int `json:"table_cnt"`
|
SWQoSTips decimal.Decimal `json:"swqos_tips"`
|
||||||
|
TableCnt int `json:"table_cnt"`
|
||||||
|
|
||||||
ExactSOL bool `json:"exact_in"`
|
ExactSOL bool `json:"exact_in"`
|
||||||
|
|
||||||
|
|||||||
@@ -777,3 +777,122 @@ func TestParseRaydiumLaunchLabCreate2(t *testing.T) {
|
|||||||
t.Fatalf("expected IsToken2022 true, got false")
|
t.Fatalf("expected IsToken2022 true, got false")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user