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}
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
@@ -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) {
var (
ret pumpWrappedMatch
@@ -932,6 +962,42 @@ func pumpWrappedAtIdx0V2(in uint64, out uint64, plan []RoutePlanStepV2) (pumpWra
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) {
for i, acctIdx := range accounts {
key, err := getStaticKey(staticKeys, int(acctIdx))
@@ -953,6 +1019,43 @@ func findPumpFunMint(staticKeys []solana.PublicKey, accounts []uint8) (solana.Pu
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
func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (*TxSignal, error) {
msg := tx.Message
@@ -973,9 +1076,13 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
var (
sourceMint solana.PublicKey
inputAmount uint64
routeIn uint64
routeOut uint64
planCount int
wrapped pumpWrappedMatch
wrappedCnt int
wrappedAny pumpWrappedMatch
wrappedAnyC int
exactOut bool
err error
)
@@ -990,6 +1097,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
}
inputAmount, planCount = pumpSwapSellAtIdx0V2(args.In, 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):
args, err := decodeJupiterV6SharedAccountsRouteV2Arg(instruction.Data[8:])
if err != nil {
@@ -997,6 +1107,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
}
inputAmount, planCount = pumpSwapSellAtIdx0V2(args.In, 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):
args, err := decodeJupiterV6ExactOutRouteV2Arg(instruction.Data[8:])
if err != nil {
@@ -1004,6 +1117,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
}
exactOut = true
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):
args, err := decodeJupiterV6SharedAccountsExactOutRouteV2Arg(instruction.Data[8:])
if err != nil {
@@ -1011,6 +1127,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
}
exactOut = true
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):
args, err := decodeJupiterV6RouteArg(instruction.Data[8:])
if err != nil {
@@ -1019,6 +1138,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
_ = args
inputAmount, planCount = pumpSwapSellAtIdx0(args.In, 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):
args, err := decodeJupiterV6SharedAccountsExactOutRouteArg(instruction.Data[8:])
if err != nil {
@@ -1026,6 +1148,9 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
}
exactOut = true
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):
args, err := decodeJupiterV6SharedAccountsRouteArg(instruction.Data[8:])
if err != nil {
@@ -1034,9 +1159,74 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
_ = args
inputAmount, planCount = pumpSwapSellAtIdx0(args.In, args.Plan)
wrapped, wrappedCnt = pumpWrappedAtIdx0(args.In, args.QuotedOut, args.Plan)
wrappedAny, wrappedAnyC = pumpWrappedAny(args.Plan)
routeIn = args.In
routeOut = args.QuotedOut
default:
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 {
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 {
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 (
@@ -1070,13 +1285,106 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
}
token1Amount := decimal.Zero
if token1AmountUint64 > 0 {
token1Amount = formatSolAmount(token1AmountUint64)
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: 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,
Token1Amount: token1Amount,
Program: "Pump",