Files
pump-parser/swap_amounts_test.go

207 lines
6.2 KiB
Go
Raw Permalink Normal View History

2026-04-16 14:24:14 +08:00
package pump_parser
import (
"testing"
"github.com/gagliardetto/solana-go"
"github.com/shopspring/decimal"
)
func TestSetSwapAmountInfoExactInBuy(t *testing.T) {
swap := Swap{
Event: TxEventBuy,
BaseMint: solana.MustPublicKeyFromBase58("11111111111111111111111111111111"),
QuoteMint: solana.MustPublicKeyFromBase58("So11111111111111111111111111111111111111112"),
BaseAmount: decimal.NewFromInt(120),
QuoteAmount: decimal.NewFromInt(100),
}
swap.SetSwapAmountInfo(SwapModeExactIn, decimal.NewFromInt(100), decimal.NewFromInt(110))
if swap.FixedAmountSide != SwapAmountSideQuote {
t.Fatalf("fixed side = %s, want quote", swap.FixedAmountSide.String())
}
if swap.LimitAmountType != SwapLimitTypeMinOut {
t.Fatalf("limit type = %s, want min_out", swap.LimitAmountType.String())
}
if swap.LimitAmountSide != SwapAmountSideBase {
t.Fatalf("limit side = %s, want base", swap.LimitAmountSide.String())
}
if !swap.ActualLimitAmount.Equal(decimal.NewFromInt(120)) {
t.Fatalf("actual limit amount = %s, want 120", swap.ActualLimitAmount)
}
if got := swap.SlippageBps.StringFixed(4); got != "833.3333" {
t.Fatalf("slippage bps = %s, want 833.3333", got)
}
}
func TestSetSwapAmountInfoExactOutSell(t *testing.T) {
swap := Swap{
Event: TxEventSell,
BaseMint: solana.MustPublicKeyFromBase58("11111111111111111111111111111111"),
QuoteMint: solana.MustPublicKeyFromBase58("So11111111111111111111111111111111111111112"),
BaseAmount: decimal.NewFromInt(95),
QuoteAmount: decimal.NewFromInt(100),
}
swap.SetSwapAmountInfo(SwapModeExactOut, decimal.NewFromInt(100), decimal.NewFromInt(105))
if swap.FixedAmountSide != SwapAmountSideQuote {
t.Fatalf("fixed side = %s, want quote", swap.FixedAmountSide.String())
}
if swap.LimitAmountType != SwapLimitTypeMaxIn {
t.Fatalf("limit type = %s, want max_in", swap.LimitAmountType.String())
}
if swap.LimitAmountSide != SwapAmountSideBase {
t.Fatalf("limit side = %s, want base", swap.LimitAmountSide.String())
}
if !swap.ActualLimitAmount.Equal(decimal.NewFromInt(95)) {
t.Fatalf("actual limit amount = %s, want 95", swap.ActualLimitAmount)
}
if got := swap.SlippageBps.StringFixed(4); got != "952.3810" {
t.Fatalf("slippage bps = %s, want 952.3810", got)
}
}
func TestSetSwapAmountInfoExactInZeroLimitUsesMaxSlippage(t *testing.T) {
swap := Swap{
Event: TxEventSell,
BaseMint: solana.MustPublicKeyFromBase58("11111111111111111111111111111111"),
QuoteMint: solana.MustPublicKeyFromBase58("So11111111111111111111111111111111111111112"),
BaseAmount: decimal.NewFromInt(50),
QuoteAmount: decimal.NewFromInt(25),
}
swap.SetSwapAmountInfo(SwapModeExactIn, decimal.NewFromInt(50), decimal.Zero)
if got := swap.SlippageBps.String(); got != "10000" {
t.Fatalf("slippage bps = %s, want 10000", got)
}
}
2026-04-20 12:31:30 +08:00
func TestSetSwapAmountInfoExactInNegativeHeadroomClampsToZero(t *testing.T) {
swap := Swap{
Event: TxEventBuy,
BaseMint: solana.MustPublicKeyFromBase58("11111111111111111111111111111111"),
QuoteMint: solana.MustPublicKeyFromBase58("So11111111111111111111111111111111111111112"),
BaseAmount: decimal.NewFromInt(90),
QuoteAmount: decimal.NewFromInt(100),
}
swap.SetSwapAmountInfo(SwapModeExactIn, decimal.NewFromInt(100), decimal.NewFromInt(110))
if got := swap.SlippageBps.String(); got != "0" {
t.Fatalf("slippage bps = %s, want 0", got)
}
}
func TestSetSwapAmountInfoExactOutNegativeHeadroomClampsToZero(t *testing.T) {
swap := Swap{
Event: TxEventSell,
BaseMint: solana.MustPublicKeyFromBase58("11111111111111111111111111111111"),
QuoteMint: solana.MustPublicKeyFromBase58("So11111111111111111111111111111111111111112"),
BaseAmount: decimal.NewFromInt(120),
QuoteAmount: decimal.NewFromInt(100),
}
swap.SetSwapAmountInfo(SwapModeExactOut, decimal.NewFromInt(100), decimal.NewFromInt(105))
if got := swap.SlippageBps.String(); got != "0" {
t.Fatalf("slippage bps = %s, want 0", got)
}
}
2026-04-16 14:24:14 +08:00
func TestMeteoraDammSwapAmountInfo(t *testing.T) {
tests := []struct {
name string
event string
params *struct {
Amount0 uint64
Amount1 uint64
SwapMode uint8
}
wantMode SwapMode
wantFixed int64
wantLimit int64
}{
{
name: "sell exact in uses amount0 as input and amount1 as min out",
event: TxEventSell,
params: &struct {
Amount0 uint64
Amount1 uint64
SwapMode uint8
}{Amount0: 100, Amount1: 95, SwapMode: 0},
wantMode: SwapModeExactIn,
wantFixed: 100,
wantLimit: 95,
},
{
name: "sell partial fill follows exact in semantics",
event: TxEventSell,
params: &struct {
Amount0 uint64
Amount1 uint64
SwapMode uint8
}{Amount0: 101, Amount1: 96, SwapMode: 1},
wantMode: SwapModeExactIn,
wantFixed: 101,
wantLimit: 96,
},
2026-04-20 12:31:30 +08:00
{
name: "buy exact in keeps amount0 as input and amount1 as min out",
event: TxEventBuy,
params: &struct {
Amount0 uint64
Amount1 uint64
SwapMode uint8
}{Amount0: 130, Amount1: 120, SwapMode: 0},
wantMode: SwapModeExactIn,
wantFixed: 130,
wantLimit: 120,
},
2026-04-16 14:24:14 +08:00
{
name: "buy exact out uses amount0 as target output and amount1 as max input",
event: TxEventBuy,
params: &struct {
Amount0 uint64
Amount1 uint64
SwapMode uint8
}{Amount0: 120, Amount1: 130, SwapMode: 2},
wantMode: SwapModeExactOut,
wantFixed: 120,
wantLimit: 130,
},
2026-04-20 12:31:30 +08:00
{
name: "sell exact out keeps amount0 as target output and amount1 as max input",
event: TxEventSell,
params: &struct {
Amount0 uint64
Amount1 uint64
SwapMode uint8
}{Amount0: 140, Amount1: 150, SwapMode: 2},
wantMode: SwapModeExactOut,
wantFixed: 140,
wantLimit: 150,
},
2026-04-16 14:24:14 +08:00
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotMode, gotFixed, gotLimit, ok := meteoraDammSwapAmountInfo(tt.event, tt.params)
if !ok {
t.Fatal("ok = false, want true")
}
if gotMode != tt.wantMode {
t.Fatalf("mode = %s, want %s", gotMode.String(), tt.wantMode.String())
}
if !gotFixed.Equal(decimal.NewFromInt(tt.wantFixed)) {
t.Fatalf("fixed = %s, want %d", gotFixed, tt.wantFixed)
}
if !gotLimit.Equal(decimal.NewFromInt(tt.wantLimit)) {
t.Fatalf("limit = %s, want %d", gotLimit, tt.wantLimit)
}
})
}
}