package pump_parser import ( "encoding/json" "github.com/gagliardetto/solana-go" "github.com/shopspring/decimal" ) var maxSlippageBps = decimal.NewFromInt(10000) type SwapMode uint8 type SwapAmountSide uint8 type SwapLimitType uint8 const ( SwapModeUnknown SwapMode = iota SwapModeExactIn SwapModeExactOut ) const ( SwapAmountSideUnknown SwapAmountSide = iota SwapAmountSideBase SwapAmountSideQuote ) const ( SwapLimitTypeUnknown SwapLimitType = iota SwapLimitTypeMinOut SwapLimitTypeMaxIn ) func (m SwapMode) String() string { switch m { case SwapModeExactIn: return "exact_in" case SwapModeExactOut: return "exact_out" default: return "" } } func (m SwapMode) MarshalJSON() ([]byte, error) { return json.Marshal(m.String()) } func (s SwapAmountSide) String() string { switch s { case SwapAmountSideBase: return "base" case SwapAmountSideQuote: return "quote" default: return "" } } func (s SwapAmountSide) MarshalJSON() ([]byte, error) { return json.Marshal(s.String()) } func (t SwapLimitType) String() string { switch t { case SwapLimitTypeMinOut: return "min_out" case SwapLimitTypeMaxIn: return "max_in" default: return "" } } func (t SwapLimitType) MarshalJSON() ([]byte, error) { return json.Marshal(t.String()) } func swapAmountForSide(baseAmount, quoteAmount decimal.Decimal, side SwapAmountSide) decimal.Decimal { switch side { case SwapAmountSideBase: return baseAmount case SwapAmountSideQuote: return quoteAmount default: return decimal.Zero } } func swapMintForSide(baseMint, quoteMint solana.PublicKey, side SwapAmountSide) solana.PublicKey { switch side { case SwapAmountSideBase: return baseMint case SwapAmountSideQuote: return quoteMint default: return solana.PublicKey{} } } func oppositeSwapAmountSide(side SwapAmountSide) SwapAmountSide { switch side { case SwapAmountSideBase: return SwapAmountSideQuote case SwapAmountSideQuote: return SwapAmountSideBase default: return SwapAmountSideUnknown } } func fixedSwapAmountSide(event string, swapMode SwapMode) SwapAmountSide { switch swapMode { case SwapModeExactIn: switch event { case TxEventBuy: return SwapAmountSideQuote case TxEventSell: return SwapAmountSideBase } case SwapModeExactOut: switch event { case TxEventBuy: return SwapAmountSideBase case TxEventSell: return SwapAmountSideQuote } } return SwapAmountSideUnknown } func limitSwapAmountType(swapMode SwapMode) SwapLimitType { switch swapMode { case SwapModeExactIn: return SwapLimitTypeMinOut case SwapModeExactOut: return SwapLimitTypeMaxIn default: return SwapLimitTypeUnknown } } func calculateLimitSlippageBps(limitType SwapLimitType, limitAmount, actualAmount decimal.Decimal) decimal.Decimal { switch limitType { case SwapLimitTypeMinOut: if !actualAmount.IsPositive() { if !limitAmount.IsPositive() { return maxSlippageBps } return maxSlippageBps.Neg() } if !limitAmount.IsPositive() { return maxSlippageBps } return actualAmount.Sub(limitAmount).Mul(maxSlippageBps).Div(actualAmount) case SwapLimitTypeMaxIn: if !limitAmount.IsPositive() { if !actualAmount.IsPositive() { return maxSlippageBps } return maxSlippageBps.Neg() } return limitAmount.Sub(actualAmount).Mul(maxSlippageBps).Div(limitAmount) default: return decimal.Zero } } func (s *Swap) SetSwapAmountInfoDetailed( swapMode SwapMode, fixedAmount decimal.Decimal, fixedSide SwapAmountSide, fixedMint solana.PublicKey, limitType SwapLimitType, limitAmount decimal.Decimal, limitSide SwapAmountSide, limitMint solana.PublicKey, actualLimitAmount decimal.Decimal, ) { s.SwapMode = swapMode s.FixedAmount = fixedAmount s.FixedAmountSide = fixedSide s.FixedMint = fixedMint s.LimitAmountType = limitType s.LimitAmount = limitAmount s.LimitAmountSide = limitSide s.LimitMint = limitMint s.ActualLimitAmount = actualLimitAmount s.ActualLimitAmountSide = limitSide s.SlippageBps = calculateLimitSlippageBps(limitType, limitAmount, actualLimitAmount) } func (s *Swap) SetSwapAmountInfo(swapMode SwapMode, fixedAmount, limitAmount decimal.Decimal) { fixedSide := fixedSwapAmountSide(s.Event, swapMode) if fixedSide == SwapAmountSideUnknown { return } limitType := limitSwapAmountType(swapMode) limitSide := oppositeSwapAmountSide(fixedSide) actualLimitAmount := swapAmountForSide(s.BaseAmount, s.QuoteAmount, limitSide) s.SetSwapAmountInfoDetailed( swapMode, fixedAmount, fixedSide, swapMintForSide(s.BaseMint, s.QuoteMint, fixedSide), limitType, limitAmount, limitSide, swapMintForSide(s.BaseMint, s.QuoteMint, limitSide), actualLimitAmount, ) }