package pump_parser import ( "encoding/base64" "encoding/binary" "testing" "github.com/gagliardetto/solana-go" ) func TestMetaoraPoolSwapEventFromLogsUsesMatchingInvocation(t *testing.T) { firstEvent := metaoraPoolSwapEventLogForTest(10, 9, 1, 0, 0) secondEvent := metaoraPoolSwapEventLogForTest(4013522650, 135, 8043041, 2010760, 0) logs := []string{ "Program " + metaoraPoolProgramID.String() + " invoke [1]", "Program log: Instruction: Swap", "Program data: " + firstEvent, "Program " + metaoraPoolProgramID.String() + " success", "Program " + solana.TokenProgramID.String() + " invoke [1]", "Program data: " + secondEvent, "Program " + solana.TokenProgramID.String() + " success", "Program " + metaoraPoolProgramID.String() + " invoke [1]", "Program log: Instruction: Swap", "Program data: " + secondEvent, "Program " + metaoraPoolProgramID.String() + " success", } event, ok := metaoraPoolSwapEventFromLogs(logs, 2) if !ok { t.Fatal("expected second swap event") } if event.InAmount != 4013522650 { t.Fatalf("in amount = %d, want 4013522650", event.InAmount) } if event.OutAmount != 135 { t.Fatalf("out amount = %d, want 135", event.OutAmount) } if event.TradeFee != 8043041 { t.Fatalf("trade fee = %d, want 8043041", event.TradeFee) } if event.ProtocolFee != 2010760 { t.Fatalf("protocol fee = %d, want 2010760", event.ProtocolFee) } } func TestMetaoraPoolSwapInstructionOccurrenceIncludesInnerInstructions(t *testing.T) { rawTx := &RawTx{ Transaction: Transaction{ Message: Message{ AccountKeys: solana.PublicKeySlice{ metaoraPoolProgramID, solana.MustPublicKeyFromBase58("BASDaPs2cdVTsvgPRfESDLZgek8tKRTfqbR2ksdgptsn"), }, Instructions: []Instruction{ {ProgramIDIndex: 0, Data: metaoraPoolSwapInstructionDataForTest()}, {ProgramIDIndex: 1, Data: []byte{1}}, }, }, }, Meta: Meta{ InnerInstructions: []InnerInstructions{ { Index: 1, Instructions: []Instruction{ {ProgramIDIndex: 0, Data: metaoraPoolSwapInstructionDataForTest()}, }, }, }, }, } if got := metaoraPoolSwapInstructionOccurrence(rawTx, [2]uint{1, 1}); got != 2 { t.Fatalf("occurrence = %d, want 2", got) } } func TestAttachLogEventsToInstructions(t *testing.T) { swapEvent := metaoraPoolSwapEventLogForTest(4013522650, 135, 8043041, 2010760, 0) rawTx := &RawTx{ Transaction: Transaction{ Message: Message{ AccountKeys: solana.PublicKeySlice{ metaoraPoolProgramID, solana.TokenProgramID, }, Instructions: []Instruction{ {ProgramIDIndex: 0, Data: metaoraPoolSwapInstructionDataForTest()}, }, }, }, Meta: Meta{ InnerInstructions: []InnerInstructions{ { Index: 0, Instructions: []Instruction{ {ProgramIDIndex: 1, Data: []byte{3}, StackHeight: intPtrForTest(2)}, }, }, }, LogMessages: []string{ "Program " + metaoraPoolProgramID.String() + " invoke [1]", "Program log: Instruction: Swap", "Program " + solana.TokenProgramID.String() + " invoke [2]", "Program " + solana.TokenProgramID.String() + " success", "Program data: " + swapEvent, "Program " + metaoraPoolProgramID.String() + " success", }, }, } applyRawTxConvertLogOptions(rawTx, RawTxConvertOptions{ParseLogEvents: true, IgnoreLogMessages: true}) if len(rawTx.Meta.LogMessages) != 0 { t.Fatalf("log messages length = %d, want 0", len(rawTx.Meta.LogMessages)) } if len(rawTx.Transaction.Message.Instructions[0].LogEvents) != 1 { t.Fatalf("outer log events length = %d, want 1", len(rawTx.Transaction.Message.Instructions[0].LogEvents)) } if len(rawTx.Meta.InnerInstructions[0].Instructions[0].LogEvents) != 0 { t.Fatalf("inner log events length = %d, want 0", len(rawTx.Meta.InnerInstructions[0].Instructions[0].LogEvents)) } event, ok := metaoraPoolSwapEventFromInstruction(rawTx.Transaction.Message.Instructions[0]) if !ok { t.Fatal("expected swap event from outer instruction") } if event.OutAmount != 135 { t.Fatalf("out amount = %d, want 135", event.OutAmount) } } func metaoraPoolSwapInstructionDataForTest() []byte { data := make([]byte, 8+16) copy(data, metaoraPoolSwapDiscriminator[:]) return data } func metaoraPoolSwapEventLogForTest(inAmount, outAmount, tradeFee, protocolFee, hostFee uint64) string { data := make([]byte, 8+40) copy(data, metaoraPoolSwapEventDiscriminator[:]) binary.LittleEndian.PutUint64(data[8:16], inAmount) binary.LittleEndian.PutUint64(data[16:24], outAmount) binary.LittleEndian.PutUint64(data[24:32], tradeFee) binary.LittleEndian.PutUint64(data[32:40], protocolFee) binary.LittleEndian.PutUint64(data[40:48], hostFee) return base64.StdEncoding.EncodeToString(data) } func intPtrForTest(value int) *int { return &value }