swap amount input

This commit is contained in:
thloyi
2026-04-16 14:24:14 +08:00
parent ab0e87a48a
commit e761fd6f84
29 changed files with 1542 additions and 214 deletions

213
swap_amounts.go Normal file
View File

@@ -0,0 +1,213 @@
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,
)
}