Update juptier pumpfun usdc usdt usd1 filter

This commit is contained in:
bijianing97
2026-01-23 15:07:03 +08:00
parent 594c46a1d2
commit 741d333e1b

View File

@@ -22,6 +22,10 @@ var (
jupiterSharedAccountsExactOutRouteV2 = []byte{53, 96, 229, 202, 216, 187, 250, 24} jupiterSharedAccountsExactOutRouteV2 = []byte{53, 96, 229, 202, 216, 187, 250, 24}
jupiterSharedAccountsRouteV2 = []byte{209, 152, 83, 147, 124, 254, 216, 233} jupiterSharedAccountsRouteV2 = []byte{209, 152, 83, 147, 124, 254, 216, 233}
usdcMint = solana.MustPublicKeyFromBase58("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
usd1Mint = solana.MustPublicKeyFromBase58("USD1ttGY1N17NEEHLmELoaybftRBUSErhqYiQzvEmuB")
usdtMint = solana.MustPublicKeyFromBase58("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB")
) )
type Side uint8 type Side uint8
@@ -882,6 +886,32 @@ func isPumpWrappedSell(kind SwapKind) bool {
} }
} }
func isStableMint(mint solana.PublicKey) bool {
if mint.Equals(usdcMint) {
return true
}
if mint.Equals(usd1Mint) {
return true
}
if mint.Equals(usdtMint) {
return true
}
return false
}
func isToken1Mint(mint solana.PublicKey) bool {
return mint.Equals(solana.WrappedSol) || mint.Equals(solana.SystemProgramID) || isStableMint(mint)
}
func isJupiterV6Token1RequiredDisc(disc []byte) bool {
return bytes.Equal(disc, jupiterRouteV2) ||
bytes.Equal(disc, jupiterSharedAccountsRouteV2) ||
bytes.Equal(disc, jupiterExactOutRouteV2) ||
bytes.Equal(disc, jupiterSharedAccountsExactOutRouteV2) ||
bytes.Equal(disc, jupiterSharedAccountsRoute) ||
bytes.Equal(disc, jupiterSharedAccountsExactOutRoute)
}
func pumpWrappedAtIdx0(in uint64, out uint64, plan []RoutePlanStep) (pumpWrappedMatch, int) { func pumpWrappedAtIdx0(in uint64, out uint64, plan []RoutePlanStep) (pumpWrappedMatch, int) {
var ( var (
ret pumpWrappedMatch ret pumpWrappedMatch
@@ -932,6 +962,42 @@ func pumpWrappedAtIdx0V2(in uint64, out uint64, plan []RoutePlanStepV2) (pumpWra
return ret, count return ret, count
} }
func pumpWrappedAny(plan []RoutePlanStep) (pumpWrappedMatch, int) {
var (
ret pumpWrappedMatch
count int
)
for _, step := range plan {
if !isPumpWrappedBuy(step.Swap.Kind) && !isPumpWrappedSell(step.Swap.Kind) {
continue
}
count++
if count > 1 {
return pumpWrappedMatch{}, count
}
ret.IsBuy = isPumpWrappedBuy(step.Swap.Kind)
}
return ret, count
}
func pumpWrappedAnyV2(plan []RoutePlanStepV2) (pumpWrappedMatch, int) {
var (
ret pumpWrappedMatch
count int
)
for _, step := range plan {
if !isPumpWrappedBuy(step.Swap.Kind) && !isPumpWrappedSell(step.Swap.Kind) {
continue
}
count++
if count > 1 {
return pumpWrappedMatch{}, count
}
ret.IsBuy = isPumpWrappedBuy(step.Swap.Kind)
}
return ret, count
}
func findPumpFunMint(staticKeys []solana.PublicKey, accounts []uint8) (solana.PublicKey, bool, error) { func findPumpFunMint(staticKeys []solana.PublicKey, accounts []uint8) (solana.PublicKey, bool, error) {
for i, acctIdx := range accounts { for i, acctIdx := range accounts {
key, err := getStaticKey(staticKeys, int(acctIdx)) key, err := getStaticKey(staticKeys, int(acctIdx))
@@ -953,6 +1019,43 @@ func findPumpFunMint(staticKeys []solana.PublicKey, accounts []uint8) (solana.Pu
return solana.PublicKey{}, false, nil return solana.PublicKey{}, false, nil
} }
func jupiterV6SourceDestMints(msg versionedMessage, instruction compiledInstruction, disc []byte) (solana.PublicKey, solana.PublicKey, bool, error) {
switch {
case bytes.Equal(disc, jupiterRouteV2),
bytes.Equal(disc, jupiterSharedAccountsRouteV2),
bytes.Equal(disc, jupiterExactOutRouteV2),
bytes.Equal(disc, jupiterSharedAccountsExactOutRouteV2):
if len(instruction.Accounts) < 5 {
return solana.PublicKey{}, solana.PublicKey{}, false, fmt.Errorf("not enough accounts for jupiter v6 v2 instruction")
}
src, err := getStaticKey(msg.StaticAccountKeys, int(instruction.Accounts[3]))
if err != nil {
return solana.PublicKey{}, solana.PublicKey{}, false, err
}
dst, err := getStaticKey(msg.StaticAccountKeys, int(instruction.Accounts[4]))
if err != nil {
return solana.PublicKey{}, solana.PublicKey{}, false, err
}
return src, dst, true, nil
case bytes.Equal(disc, jupiterSharedAccountsRoute),
bytes.Equal(disc, jupiterSharedAccountsExactOutRoute):
if len(instruction.Accounts) < 9 {
return solana.PublicKey{}, solana.PublicKey{}, false, fmt.Errorf("not enough accounts for jupiter v6 shared accounts instruction")
}
src, err := getStaticKey(msg.StaticAccountKeys, int(instruction.Accounts[7]))
if err != nil {
return solana.PublicKey{}, solana.PublicKey{}, false, err
}
dst, err := getStaticKey(msg.StaticAccountKeys, int(instruction.Accounts[8]))
if err != nil {
return solana.PublicKey{}, solana.PublicKey{}, false, err
}
return src, dst, true, nil
default:
return solana.PublicKey{}, solana.PublicKey{}, false, nil
}
}
// only decodes inputIdx = 0 container pumpSwap instructions for now // only decodes inputIdx = 0 container pumpSwap instructions for now
func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (*TxSignal, error) { func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (*TxSignal, error) {
msg := tx.Message msg := tx.Message
@@ -973,9 +1076,13 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
var ( var (
sourceMint solana.PublicKey sourceMint solana.PublicKey
inputAmount uint64 inputAmount uint64
routeIn uint64
routeOut uint64
planCount int planCount int
wrapped pumpWrappedMatch wrapped pumpWrappedMatch
wrappedCnt int wrappedCnt int
wrappedAny pumpWrappedMatch
wrappedAnyC int
exactOut bool exactOut bool
err error err error
) )
@@ -990,6 +1097,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
} }
inputAmount, planCount = pumpSwapSellAtIdx0V2(args.In, args.Plan) inputAmount, planCount = pumpSwapSellAtIdx0V2(args.In, args.Plan)
wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.In, args.Out, args.Plan) wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.In, args.Out, args.Plan)
wrappedAny, wrappedAnyC = pumpWrappedAnyV2(args.Plan)
routeIn = args.In
routeOut = args.Out
case bytes.Equal(disc, jupiterSharedAccountsRouteV2): case bytes.Equal(disc, jupiterSharedAccountsRouteV2):
args, err := decodeJupiterV6SharedAccountsRouteV2Arg(instruction.Data[8:]) args, err := decodeJupiterV6SharedAccountsRouteV2Arg(instruction.Data[8:])
if err != nil { if err != nil {
@@ -997,6 +1107,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
} }
inputAmount, planCount = pumpSwapSellAtIdx0V2(args.In, args.RoutePlan) inputAmount, planCount = pumpSwapSellAtIdx0V2(args.In, args.RoutePlan)
wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.In, args.QuotedOut, args.RoutePlan) wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.In, args.QuotedOut, args.RoutePlan)
wrappedAny, wrappedAnyC = pumpWrappedAnyV2(args.RoutePlan)
routeIn = args.In
routeOut = args.QuotedOut
case bytes.Equal(disc, jupiterExactOutRouteV2): case bytes.Equal(disc, jupiterExactOutRouteV2):
args, err := decodeJupiterV6ExactOutRouteV2Arg(instruction.Data[8:]) args, err := decodeJupiterV6ExactOutRouteV2Arg(instruction.Data[8:])
if err != nil { if err != nil {
@@ -1004,6 +1117,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
} }
exactOut = true exactOut = true
wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.QuotedIn, args.Out, args.RoutePlan) wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.QuotedIn, args.Out, args.RoutePlan)
wrappedAny, wrappedAnyC = pumpWrappedAnyV2(args.RoutePlan)
routeIn = args.QuotedIn
routeOut = args.Out
case bytes.Equal(disc, jupiterSharedAccountsExactOutRouteV2): case bytes.Equal(disc, jupiterSharedAccountsExactOutRouteV2):
args, err := decodeJupiterV6SharedAccountsExactOutRouteV2Arg(instruction.Data[8:]) args, err := decodeJupiterV6SharedAccountsExactOutRouteV2Arg(instruction.Data[8:])
if err != nil { if err != nil {
@@ -1011,6 +1127,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
} }
exactOut = true exactOut = true
wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.QuotedIn, args.Out, args.RoutePlan) wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.QuotedIn, args.Out, args.RoutePlan)
wrappedAny, wrappedAnyC = pumpWrappedAnyV2(args.RoutePlan)
routeIn = args.QuotedIn
routeOut = args.Out
case bytes.Equal(disc, jupiterRoute): case bytes.Equal(disc, jupiterRoute):
args, err := decodeJupiterV6RouteArg(instruction.Data[8:]) args, err := decodeJupiterV6RouteArg(instruction.Data[8:])
if err != nil { if err != nil {
@@ -1019,6 +1138,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
_ = args _ = args
inputAmount, planCount = pumpSwapSellAtIdx0(args.In, args.Plan) inputAmount, planCount = pumpSwapSellAtIdx0(args.In, args.Plan)
wrapped, wrappedCnt = pumpWrappedAtIdx0(args.In, args.QuotedOut, args.Plan) wrapped, wrappedCnt = pumpWrappedAtIdx0(args.In, args.QuotedOut, args.Plan)
wrappedAny, wrappedAnyC = pumpWrappedAny(args.Plan)
routeIn = args.In
routeOut = args.QuotedOut
case bytes.Equal(disc, jupiterSharedAccountsExactOutRoute): case bytes.Equal(disc, jupiterSharedAccountsExactOutRoute):
args, err := decodeJupiterV6SharedAccountsExactOutRouteArg(instruction.Data[8:]) args, err := decodeJupiterV6SharedAccountsExactOutRouteArg(instruction.Data[8:])
if err != nil { if err != nil {
@@ -1026,6 +1148,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
} }
exactOut = true exactOut = true
wrapped, wrappedCnt = pumpWrappedAtIdx0(args.QuotedIn, args.Out, args.Plan) wrapped, wrappedCnt = pumpWrappedAtIdx0(args.QuotedIn, args.Out, args.Plan)
wrappedAny, wrappedAnyC = pumpWrappedAny(args.Plan)
routeIn = args.QuotedIn
routeOut = args.Out
case bytes.Equal(disc, jupiterSharedAccountsRoute): case bytes.Equal(disc, jupiterSharedAccountsRoute):
args, err := decodeJupiterV6SharedAccountsRouteArg(instruction.Data[8:]) args, err := decodeJupiterV6SharedAccountsRouteArg(instruction.Data[8:])
if err != nil { if err != nil {
@@ -1034,9 +1159,74 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
_ = args _ = args
inputAmount, planCount = pumpSwapSellAtIdx0(args.In, args.Plan) inputAmount, planCount = pumpSwapSellAtIdx0(args.In, args.Plan)
wrapped, wrappedCnt = pumpWrappedAtIdx0(args.In, args.QuotedOut, args.Plan) wrapped, wrappedCnt = pumpWrappedAtIdx0(args.In, args.QuotedOut, args.Plan)
wrappedAny, wrappedAnyC = pumpWrappedAny(args.Plan)
routeIn = args.In
routeOut = args.QuotedOut
default: default:
return nil, nil return nil, nil
} }
if bytes.Equal(disc, jupiterRoute) {
if len(instruction.Accounts) < 13 {
return nil, nil
}
destMint, err := getStaticKey(tx.Message.StaticAccountKeys, int(instruction.Accounts[5]))
if err != nil {
return nil, err
}
if isToken1Mint(destMint) {
pumpKey, err := getStaticKey(tx.Message.StaticAccountKeys, int(instruction.Accounts[9]))
if err != nil {
return nil, err
}
if !pumpKey.Equals(pumpProgramID) {
return nil, nil
}
token0Mint, err := getStaticKey(tx.Message.StaticAccountKeys, int(instruction.Accounts[12]))
if err != nil {
return nil, err
}
token0Amount := decimal.Zero
if routeIn > 0 {
token0Amount = formatTokenAmount(routeIn)
}
return &TxSignal{
TxHash: tx.Signatures[0].String(),
Maker: tx.Message.StaticAccountKeys[0].String(),
Token0Address: token0Mint.String(),
Token1Address: destMint.String(),
Token0Amount: token0Amount,
Token1Amount: decimal.Zero,
Program: "Pump",
Event: "sell",
IsToken2022: false,
IsMayhemMode: false,
ExactSOL: false,
Block: tx.Block,
Token0AmountUint64: routeIn,
Token1AmountUint64: 0,
}, nil
}
token0Amount := decimal.Zero
if routeOut > 0 {
token0Amount = formatTokenAmount(routeOut)
}
return &TxSignal{
TxHash: tx.Signatures[0].String(),
Maker: tx.Message.StaticAccountKeys[0].String(),
Token0Address: destMint.String(),
Token1Address: wsolMint,
Token0Amount: token0Amount,
Token1Amount: decimal.Zero,
Program: "Pump",
Event: "buy",
IsToken2022: false,
IsMayhemMode: false,
ExactSOL: false,
Block: tx.Block,
Token0AmountUint64: routeOut,
Token1AmountUint64: 0,
}, nil
}
if wrappedCnt > 1 { if wrappedCnt > 1 {
logger.Warn("pumpWrapped at inputIdx=0: multiple instances found", "tx", tx.Signatures[0].String(), "planCount", wrappedCnt) logger.Warn("pumpWrapped at inputIdx=0: multiple instances found", "tx", tx.Signatures[0].String(), "planCount", wrappedCnt)
} }
@@ -1048,6 +1238,31 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
if !ok { if !ok {
return nil, nil return nil, nil
} }
token1Mint := solana.WrappedSol
token1IsStable := false
srcMint, dstMint, ok, err := jupiterV6SourceDestMints(tx.Message, instruction, disc)
if err != nil {
return nil, err
}
if isJupiterV6Token1RequiredDisc(disc) {
if !ok {
return nil, nil
}
if !isToken1Mint(srcMint) && !isToken1Mint(dstMint) {
return nil, nil
}
}
if ok {
if srcMint.Equals(solana.WrappedSol) || dstMint.Equals(solana.WrappedSol) {
token1Mint = solana.WrappedSol
} else if isStableMint(srcMint) {
token1Mint = srcMint
token1IsStable = true
} else if isStableMint(dstMint) {
token1Mint = dstMint
token1IsStable = true
}
}
event := "sell" event := "sell"
exactSol := false exactSol := false
var ( var (
@@ -1070,13 +1285,106 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
} }
token1Amount := decimal.Zero token1Amount := decimal.Zero
if token1AmountUint64 > 0 { if token1AmountUint64 > 0 {
if token1IsStable {
token1Amount = formatTokenAmount(token1AmountUint64)
} else {
token1Amount = formatSolAmount(token1AmountUint64) token1Amount = formatSolAmount(token1AmountUint64)
} }
}
token1Address := wsolMint
if token1IsStable {
token1Address = token1Mint.String()
}
return &TxSignal{ return &TxSignal{
TxHash: tx.Signatures[0].String(), TxHash: tx.Signatures[0].String(),
Maker: tx.Message.StaticAccountKeys[0].String(), Maker: tx.Message.StaticAccountKeys[0].String(),
Token0Address: mint.String(), Token0Address: mint.String(),
Token1Address: wsolMint, Token1Address: token1Address,
Token0Amount: token0Amount,
Token1Amount: token1Amount,
Program: "Pump",
Event: event,
IsToken2022: false,
IsMayhemMode: false,
ExactSOL: exactSol,
Block: tx.Block,
Token0AmountUint64: token0AmountUint64,
Token1AmountUint64: token1AmountUint64,
}, nil
}
if wrappedAnyC > 1 {
logger.Warn("pumpWrapped at inputIdx!=0: multiple instances found", "tx", tx.Signatures[0].String(), "planCount", wrappedAnyC)
}
if wrappedAnyC == 1 && routeIn > 0 && routeOut > 0 {
mint, ok, err := findPumpFunMint(tx.Message.StaticAccountKeys, instruction.Accounts)
if err != nil {
return nil, err
}
if !ok {
return nil, nil
}
token1Mint := solana.WrappedSol
token1IsStable := false
srcMint, dstMint, ok, err := jupiterV6SourceDestMints(tx.Message, instruction, disc)
if err != nil {
return nil, err
}
if isJupiterV6Token1RequiredDisc(disc) {
if !ok {
return nil, nil
}
if !isToken1Mint(srcMint) && !isToken1Mint(dstMint) {
return nil, nil
}
}
if ok {
if srcMint.Equals(solana.WrappedSol) || dstMint.Equals(solana.WrappedSol) {
token1Mint = solana.WrappedSol
} else if isStableMint(srcMint) {
token1Mint = srcMint
token1IsStable = true
} else if isStableMint(dstMint) {
token1Mint = dstMint
token1IsStable = true
}
}
event := "sell"
exactSol := false
var (
token0AmountUint64 uint64
token1AmountUint64 uint64
)
if wrappedAny.IsBuy {
event = "buy"
exactSol = !exactOut
token0AmountUint64 = routeOut
token1AmountUint64 = routeIn
} else {
exactSol = exactOut && routeOut > 0
token0AmountUint64 = routeIn
token1AmountUint64 = routeOut
}
token0Amount := decimal.Zero
if token0AmountUint64 > 0 {
token0Amount = formatTokenAmount(token0AmountUint64)
}
token1Amount := decimal.Zero
if token1AmountUint64 > 0 {
if token1IsStable {
token1Amount = formatTokenAmount(token1AmountUint64)
} else {
token1Amount = formatSolAmount(token1AmountUint64)
}
}
token1Address := wsolMint
if token1IsStable {
token1Address = token1Mint.String()
}
return &TxSignal{
TxHash: tx.Signatures[0].String(),
Maker: tx.Message.StaticAccountKeys[0].String(),
Token0Address: mint.String(),
Token1Address: token1Address,
Token0Amount: token0Amount, Token0Amount: token0Amount,
Token1Amount: token1Amount, Token1Amount: token1Amount,
Program: "Pump", Program: "Pump",