Add jupiter pumpamm buy pase
This commit is contained in:
@@ -823,21 +823,43 @@ func decodeJupiterV6SharedAccountsRouteV2Arg(data []byte) (*JupiterV6SharedAccou
|
|||||||
return &JupiterV6SharedAccountsRouteV2Arg{ID: id, In: inAmt, QuotedOut: quotedOut, Slippage: slippage, PlatFee: pf, PosSlip: pos, RoutePlan: plan}, nil
|
return &JupiterV6SharedAccountsRouteV2Arg{ID: id, In: inAmt, QuotedOut: quotedOut, Slippage: slippage, PlatFee: pf, PosSlip: pos, RoutePlan: plan}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isInputIdx0(idx uint8) bool {
|
||||||
|
return idx == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPumpSwapSellKind(kind SwapKind) bool {
|
||||||
|
switch kind {
|
||||||
|
case PumpSwapSell, PumpSwapSellV2, PumpSwapSellV3:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPumpSwapBuyKind(kind SwapKind) bool {
|
||||||
|
switch kind {
|
||||||
|
case PumpSwapBuy, PumpSwapBuyV2, PumpSwapBuyV3:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func pumpSwapSellAtIdx0(amount uint64, plan []RoutePlanStep) (uint64, int) {
|
func pumpSwapSellAtIdx0(amount uint64, plan []RoutePlanStep) (uint64, int) {
|
||||||
var (
|
var (
|
||||||
ret uint64
|
ret uint64
|
||||||
i int
|
i int
|
||||||
)
|
)
|
||||||
for _, step := range plan {
|
for _, step := range plan {
|
||||||
if step.InputIdx == 0 &&
|
if !isInputIdx0(step.InputIdx) || !isPumpSwapSellKind(step.Swap.Kind) {
|
||||||
(step.Swap.Kind == PumpSwapSell || step.Swap.Kind == PumpSwapSellV2 || step.Swap.Kind == PumpSwapSellV3) {
|
continue
|
||||||
i++
|
|
||||||
if ret > 0 {
|
|
||||||
// multiple pumpSwapSell at inputIdx=0? should not happen
|
|
||||||
return 0, i
|
|
||||||
}
|
|
||||||
ret += amount * uint64(step.Percent) / 100
|
|
||||||
}
|
}
|
||||||
|
i++
|
||||||
|
if ret > 0 {
|
||||||
|
// multiple pumpSwapSell at inputIdx=0? should not happen
|
||||||
|
return 0, i
|
||||||
|
}
|
||||||
|
ret += amount * uint64(step.Percent) / 100
|
||||||
}
|
}
|
||||||
return ret, i
|
return ret, i
|
||||||
}
|
}
|
||||||
@@ -848,20 +870,66 @@ func pumpSwapSellAtIdx0V2(amount uint64, plan []RoutePlanStepV2) (uint64, int) {
|
|||||||
i int
|
i int
|
||||||
)
|
)
|
||||||
for _, step := range plan {
|
for _, step := range plan {
|
||||||
if step.InputIdx == 0 &&
|
if !isInputIdx0(step.InputIdx) || !isPumpSwapSellKind(step.Swap.Kind) {
|
||||||
(step.Swap.Kind == PumpSwapSell || step.Swap.Kind == PumpSwapSellV2 || step.Swap.Kind == PumpSwapSellV3) {
|
continue
|
||||||
i++
|
|
||||||
if ret > 0 {
|
|
||||||
// multiple pumpSwapSell at inputIdx=0? should not happen
|
|
||||||
|
|
||||||
return 0, i
|
|
||||||
}
|
|
||||||
ret += amount * uint64(step.Bps) / 10000
|
|
||||||
}
|
}
|
||||||
|
i++
|
||||||
|
if ret > 0 {
|
||||||
|
// multiple pumpSwapSell at inputIdx=0? should not happen
|
||||||
|
return 0, i
|
||||||
|
}
|
||||||
|
ret += amount * uint64(step.Bps) / 10000
|
||||||
}
|
}
|
||||||
return ret, i
|
return ret, i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type pumpSwapBuyMatch struct {
|
||||||
|
InAmount uint64
|
||||||
|
OutAmount uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func pumpSwapBuyAtIdx0(in uint64, out uint64, plan []RoutePlanStep) (pumpSwapBuyMatch, int) {
|
||||||
|
var (
|
||||||
|
ret pumpSwapBuyMatch
|
||||||
|
count int
|
||||||
|
)
|
||||||
|
for _, step := range plan {
|
||||||
|
if !isInputIdx0(step.InputIdx) || !isPumpSwapBuyKind(step.Swap.Kind) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
if count > 1 {
|
||||||
|
return pumpSwapBuyMatch{}, count
|
||||||
|
}
|
||||||
|
ret.InAmount = in * uint64(step.Percent) / 100
|
||||||
|
if step.Percent == 100 {
|
||||||
|
ret.OutAmount = out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret, count
|
||||||
|
}
|
||||||
|
|
||||||
|
func pumpSwapBuyAtIdx0V2(in uint64, out uint64, plan []RoutePlanStepV2) (pumpSwapBuyMatch, int) {
|
||||||
|
var (
|
||||||
|
ret pumpSwapBuyMatch
|
||||||
|
count int
|
||||||
|
)
|
||||||
|
for _, step := range plan {
|
||||||
|
if !isInputIdx0(step.InputIdx) || !isPumpSwapBuyKind(step.Swap.Kind) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
count++
|
||||||
|
if count > 1 {
|
||||||
|
return pumpSwapBuyMatch{}, count
|
||||||
|
}
|
||||||
|
ret.InAmount = in * uint64(step.Bps) / 10000
|
||||||
|
if step.Bps == 10000 {
|
||||||
|
ret.OutAmount = out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret, count
|
||||||
|
}
|
||||||
|
|
||||||
type pumpWrappedMatch struct {
|
type pumpWrappedMatch struct {
|
||||||
IsBuy bool
|
IsBuy bool
|
||||||
InAmount uint64
|
InAmount uint64
|
||||||
@@ -886,6 +954,10 @@ func isPumpWrappedSell(kind SwapKind) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isPumpWrappedKind(kind SwapKind) bool {
|
||||||
|
return isPumpWrappedBuy(kind) || isPumpWrappedSell(kind)
|
||||||
|
}
|
||||||
|
|
||||||
func isStableMint(mint solana.PublicKey) bool {
|
func isStableMint(mint solana.PublicKey) bool {
|
||||||
if mint.Equals(usdcMint) {
|
if mint.Equals(usdcMint) {
|
||||||
return true
|
return true
|
||||||
@@ -918,10 +990,10 @@ func pumpWrappedAtIdx0(in uint64, out uint64, plan []RoutePlanStep) (pumpWrapped
|
|||||||
count int
|
count int
|
||||||
)
|
)
|
||||||
for _, step := range plan {
|
for _, step := range plan {
|
||||||
if step.InputIdx != 0 {
|
if !isInputIdx0(step.InputIdx) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !isPumpWrappedBuy(step.Swap.Kind) && !isPumpWrappedSell(step.Swap.Kind) {
|
if !isPumpWrappedKind(step.Swap.Kind) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
@@ -943,10 +1015,10 @@ func pumpWrappedAtIdx0V2(in uint64, out uint64, plan []RoutePlanStepV2) (pumpWra
|
|||||||
count int
|
count int
|
||||||
)
|
)
|
||||||
for _, step := range plan {
|
for _, step := range plan {
|
||||||
if step.InputIdx != 0 {
|
if !isInputIdx0(step.InputIdx) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !isPumpWrappedBuy(step.Swap.Kind) && !isPumpWrappedSell(step.Swap.Kind) {
|
if !isPumpWrappedKind(step.Swap.Kind) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
@@ -968,7 +1040,7 @@ func pumpWrappedAny(plan []RoutePlanStep) (pumpWrappedMatch, int) {
|
|||||||
count int
|
count int
|
||||||
)
|
)
|
||||||
for _, step := range plan {
|
for _, step := range plan {
|
||||||
if !isPumpWrappedBuy(step.Swap.Kind) && !isPumpWrappedSell(step.Swap.Kind) {
|
if !isPumpWrappedKind(step.Swap.Kind) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
@@ -986,7 +1058,7 @@ func pumpWrappedAnyV2(plan []RoutePlanStepV2) (pumpWrappedMatch, int) {
|
|||||||
count int
|
count int
|
||||||
)
|
)
|
||||||
for _, step := range plan {
|
for _, step := range plan {
|
||||||
if !isPumpWrappedBuy(step.Swap.Kind) && !isPumpWrappedSell(step.Swap.Kind) {
|
if !isPumpWrappedKind(step.Swap.Kind) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
@@ -998,6 +1070,124 @@ func pumpWrappedAnyV2(plan []RoutePlanStepV2) (pumpWrappedMatch, int) {
|
|||||||
return ret, count
|
return ret, count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pumpRoutePlanStats(in uint64, out uint64, plan []RoutePlanStep, includeInput bool) (uint64, int, pumpSwapBuyMatch, int, pumpWrappedMatch, int, pumpWrappedMatch, int) {
|
||||||
|
var (
|
||||||
|
inputAmount uint64
|
||||||
|
planCount int
|
||||||
|
)
|
||||||
|
if includeInput {
|
||||||
|
inputAmount, planCount = pumpSwapSellAtIdx0(in, plan)
|
||||||
|
}
|
||||||
|
buySwap, buySwapCnt := pumpSwapBuyAtIdx0(in, out, plan)
|
||||||
|
wrapped, wrappedCnt := pumpWrappedAtIdx0(in, out, plan)
|
||||||
|
wrappedAny, wrappedAnyC := pumpWrappedAny(plan)
|
||||||
|
return inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC
|
||||||
|
}
|
||||||
|
|
||||||
|
func pumpRoutePlanStatsV2(in uint64, out uint64, plan []RoutePlanStepV2, includeInput bool) (uint64, int, pumpSwapBuyMatch, int, pumpWrappedMatch, int, pumpWrappedMatch, int) {
|
||||||
|
var (
|
||||||
|
inputAmount uint64
|
||||||
|
planCount int
|
||||||
|
)
|
||||||
|
if includeInput {
|
||||||
|
inputAmount, planCount = pumpSwapSellAtIdx0V2(in, plan)
|
||||||
|
}
|
||||||
|
buySwap, buySwapCnt := pumpSwapBuyAtIdx0V2(in, out, plan)
|
||||||
|
wrapped, wrappedCnt := pumpWrappedAtIdx0V2(in, out, plan)
|
||||||
|
wrappedAny, wrappedAnyC := pumpWrappedAnyV2(plan)
|
||||||
|
return inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseJupiterPumpAmmRoute(tx *versionedTransaction, instruction compiledInstruction, in uint64, out uint64, plan []RoutePlanStep) (*TxSignal, bool, error) {
|
||||||
|
var (
|
||||||
|
isBuy bool
|
||||||
|
isSell bool
|
||||||
|
count int
|
||||||
|
)
|
||||||
|
for _, step := range plan {
|
||||||
|
if !isInputIdx0(step.InputIdx) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if isPumpSwapSellKind(step.Swap.Kind) {
|
||||||
|
isSell = true
|
||||||
|
count++
|
||||||
|
} else if isPumpSwapBuyKind(step.Swap.Kind) {
|
||||||
|
isBuy = true
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
if count > 1 || (isBuy && isSell) {
|
||||||
|
logger.Warn("pumpamm route at inputIdx=0: multiple instances found", "tx", tx.Signatures[0].String(), "planCount", count)
|
||||||
|
return nil, true, nil
|
||||||
|
}
|
||||||
|
if len(instruction.Accounts) < 14 {
|
||||||
|
return nil, true, nil
|
||||||
|
}
|
||||||
|
token0Key, err := getStaticKey(tx.Message.StaticAccountKeys, int(instruction.Accounts[13]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, true, err
|
||||||
|
}
|
||||||
|
if isSell {
|
||||||
|
token0Amount := decimal.Zero
|
||||||
|
if in > 0 {
|
||||||
|
token0Amount = formatTokenAmount(in)
|
||||||
|
}
|
||||||
|
return &TxSignal{
|
||||||
|
TxHash: tx.Signatures[0].String(),
|
||||||
|
Maker: tx.Message.StaticAccountKeys[0].String(),
|
||||||
|
Token0Address: token0Key.String(),
|
||||||
|
Token1Address: wsolMint,
|
||||||
|
Token0Amount: token0Amount,
|
||||||
|
Token1Amount: decimal.Zero,
|
||||||
|
Program: "PumpAMM",
|
||||||
|
Event: "sell",
|
||||||
|
IsToken2022: false,
|
||||||
|
IsMayhemMode: false,
|
||||||
|
ExactSOL: false,
|
||||||
|
Block: tx.Block,
|
||||||
|
Token0AmountUint64: in,
|
||||||
|
Token1AmountUint64: 0,
|
||||||
|
}, true, nil
|
||||||
|
}
|
||||||
|
if len(instruction.Accounts) < 15 {
|
||||||
|
return nil, true, nil
|
||||||
|
}
|
||||||
|
wsolKey, err := getStaticKey(tx.Message.StaticAccountKeys, int(instruction.Accounts[14]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, true, err
|
||||||
|
}
|
||||||
|
if !wsolKey.Equals(solana.WrappedSol) {
|
||||||
|
return nil, true, nil
|
||||||
|
}
|
||||||
|
token0Amount := decimal.Zero
|
||||||
|
if out > 0 {
|
||||||
|
token0Amount = formatTokenAmount(out)
|
||||||
|
}
|
||||||
|
token1Amount := decimal.Zero
|
||||||
|
if in > 0 {
|
||||||
|
token1Amount = formatSolAmount(in)
|
||||||
|
}
|
||||||
|
return &TxSignal{
|
||||||
|
TxHash: tx.Signatures[0].String(),
|
||||||
|
Maker: tx.Message.StaticAccountKeys[0].String(),
|
||||||
|
Token0Address: token0Key.String(),
|
||||||
|
Token1Address: wsolMint,
|
||||||
|
Token0Amount: token0Amount,
|
||||||
|
Token1Amount: token1Amount,
|
||||||
|
Program: "PumpAMM",
|
||||||
|
Event: "buy",
|
||||||
|
IsToken2022: false,
|
||||||
|
IsMayhemMode: false,
|
||||||
|
ExactSOL: true,
|
||||||
|
Block: tx.Block,
|
||||||
|
Token0AmountUint64: out,
|
||||||
|
Token1AmountUint64: in,
|
||||||
|
}, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
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))
|
||||||
@@ -1079,6 +1269,8 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
routeIn uint64
|
routeIn uint64
|
||||||
routeOut uint64
|
routeOut uint64
|
||||||
planCount int
|
planCount int
|
||||||
|
buySwap pumpSwapBuyMatch
|
||||||
|
buySwapCnt int
|
||||||
wrapped pumpWrappedMatch
|
wrapped pumpWrappedMatch
|
||||||
wrappedCnt int
|
wrappedCnt int
|
||||||
wrappedAny pumpWrappedMatch
|
wrappedAny pumpWrappedMatch
|
||||||
@@ -1095,9 +1287,7 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
inputAmount, planCount = pumpSwapSellAtIdx0V2(args.In, args.Plan)
|
inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC = pumpRoutePlanStatsV2(args.In, args.Out, args.Plan, true)
|
||||||
wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.In, args.Out, args.Plan)
|
|
||||||
wrappedAny, wrappedAnyC = pumpWrappedAnyV2(args.Plan)
|
|
||||||
routeIn = args.In
|
routeIn = args.In
|
||||||
routeOut = args.Out
|
routeOut = args.Out
|
||||||
case bytes.Equal(disc, jupiterSharedAccountsRouteV2):
|
case bytes.Equal(disc, jupiterSharedAccountsRouteV2):
|
||||||
@@ -1105,9 +1295,7 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
inputAmount, planCount = pumpSwapSellAtIdx0V2(args.In, args.RoutePlan)
|
inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC = pumpRoutePlanStatsV2(args.In, args.QuotedOut, args.RoutePlan, true)
|
||||||
wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.In, args.QuotedOut, args.RoutePlan)
|
|
||||||
wrappedAny, wrappedAnyC = pumpWrappedAnyV2(args.RoutePlan)
|
|
||||||
routeIn = args.In
|
routeIn = args.In
|
||||||
routeOut = args.QuotedOut
|
routeOut = args.QuotedOut
|
||||||
case bytes.Equal(disc, jupiterExactOutRouteV2):
|
case bytes.Equal(disc, jupiterExactOutRouteV2):
|
||||||
@@ -1116,8 +1304,7 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
exactOut = true
|
exactOut = true
|
||||||
wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.QuotedIn, args.Out, args.RoutePlan)
|
inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC = pumpRoutePlanStatsV2(args.QuotedIn, args.Out, args.RoutePlan, false)
|
||||||
wrappedAny, wrappedAnyC = pumpWrappedAnyV2(args.RoutePlan)
|
|
||||||
routeIn = args.QuotedIn
|
routeIn = args.QuotedIn
|
||||||
routeOut = args.Out
|
routeOut = args.Out
|
||||||
case bytes.Equal(disc, jupiterSharedAccountsExactOutRouteV2):
|
case bytes.Equal(disc, jupiterSharedAccountsExactOutRouteV2):
|
||||||
@@ -1126,8 +1313,7 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
exactOut = true
|
exactOut = true
|
||||||
wrapped, wrappedCnt = pumpWrappedAtIdx0V2(args.QuotedIn, args.Out, args.RoutePlan)
|
inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC = pumpRoutePlanStatsV2(args.QuotedIn, args.Out, args.RoutePlan, false)
|
||||||
wrappedAny, wrappedAnyC = pumpWrappedAnyV2(args.RoutePlan)
|
|
||||||
routeIn = args.QuotedIn
|
routeIn = args.QuotedIn
|
||||||
routeOut = args.Out
|
routeOut = args.Out
|
||||||
case bytes.Equal(disc, jupiterRoute):
|
case bytes.Equal(disc, jupiterRoute):
|
||||||
@@ -1135,10 +1321,14 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_ = args
|
sig, handled, err := parseJupiterPumpAmmRoute(tx, instruction, args.In, args.QuotedOut, args.Plan)
|
||||||
inputAmount, planCount = pumpSwapSellAtIdx0(args.In, args.Plan)
|
if err != nil {
|
||||||
wrapped, wrappedCnt = pumpWrappedAtIdx0(args.In, args.QuotedOut, args.Plan)
|
return nil, err
|
||||||
wrappedAny, wrappedAnyC = pumpWrappedAny(args.Plan)
|
}
|
||||||
|
if handled {
|
||||||
|
return sig, nil
|
||||||
|
}
|
||||||
|
inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC = pumpRoutePlanStats(args.In, args.QuotedOut, args.Plan, true)
|
||||||
routeIn = args.In
|
routeIn = args.In
|
||||||
routeOut = args.QuotedOut
|
routeOut = args.QuotedOut
|
||||||
case bytes.Equal(disc, jupiterSharedAccountsExactOutRoute):
|
case bytes.Equal(disc, jupiterSharedAccountsExactOutRoute):
|
||||||
@@ -1147,8 +1337,7 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
exactOut = true
|
exactOut = true
|
||||||
wrapped, wrappedCnt = pumpWrappedAtIdx0(args.QuotedIn, args.Out, args.Plan)
|
inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC = pumpRoutePlanStats(args.QuotedIn, args.Out, args.Plan, false)
|
||||||
wrappedAny, wrappedAnyC = pumpWrappedAny(args.Plan)
|
|
||||||
routeIn = args.QuotedIn
|
routeIn = args.QuotedIn
|
||||||
routeOut = args.Out
|
routeOut = args.Out
|
||||||
case bytes.Equal(disc, jupiterSharedAccountsRoute):
|
case bytes.Equal(disc, jupiterSharedAccountsRoute):
|
||||||
@@ -1157,9 +1346,7 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_ = args
|
_ = args
|
||||||
inputAmount, planCount = pumpSwapSellAtIdx0(args.In, args.Plan)
|
inputAmount, planCount, buySwap, buySwapCnt, wrapped, wrappedCnt, wrappedAny, wrappedAnyC = pumpRoutePlanStats(args.In, args.QuotedOut, args.Plan, true)
|
||||||
wrapped, wrappedCnt = pumpWrappedAtIdx0(args.In, args.QuotedOut, args.Plan)
|
|
||||||
wrappedAny, wrappedAnyC = pumpWrappedAny(args.Plan)
|
|
||||||
routeIn = args.In
|
routeIn = args.In
|
||||||
routeOut = args.QuotedOut
|
routeOut = args.QuotedOut
|
||||||
default:
|
default:
|
||||||
@@ -1401,12 +1588,33 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
// multiple pumpSwapSell at inputIdx=0? should not happen
|
// multiple pumpSwapSell at inputIdx=0? should not happen
|
||||||
logger.Warn("pumpSwapSell at inputIdx=0: multiple instances found", "tx", tx.Signatures[0].String(), "planCount", planCount)
|
logger.Warn("pumpSwapSell at inputIdx=0: multiple instances found", "tx", tx.Signatures[0].String(), "planCount", planCount)
|
||||||
}
|
}
|
||||||
if inputAmount == 0 {
|
if buySwapCnt > 1 {
|
||||||
|
// multiple pumpSwapBuy at inputIdx=0? should not happen
|
||||||
|
logger.Warn("pumpSwapBuy at inputIdx=0: multiple instances found", "tx", tx.Signatures[0].String(), "planCount", buySwapCnt)
|
||||||
|
}
|
||||||
|
hasSell := inputAmount > 0
|
||||||
|
hasBuy := buySwap.InAmount > 0
|
||||||
|
if hasSell && hasBuy {
|
||||||
|
logger.Warn("pumpSwap buy/sell at inputIdx=0: both found", "tx", tx.Signatures[0].String(), "sellCount", planCount, "buyCount", buySwapCnt)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if !hasSell && !hasBuy {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseMint solana.PublicKey
|
||||||
|
quoteMint solana.PublicKey
|
||||||
|
destMint solana.PublicKey
|
||||||
|
destMintOK bool
|
||||||
|
sourceMintOK bool
|
||||||
|
)
|
||||||
|
|
||||||
// existing mint extraction logic only valid for route_v2/ exact_out_route_v2. Keep it but guard.
|
// existing mint extraction logic only valid for route_v2/ exact_out_route_v2. Keep it but guard.
|
||||||
if bytes.Equal(disc, jupiterRouteV2) || bytes.Equal(disc, jupiterSharedAccountsRouteV2) {
|
if bytes.Equal(disc, jupiterRouteV2) ||
|
||||||
|
bytes.Equal(disc, jupiterSharedAccountsRouteV2) ||
|
||||||
|
bytes.Equal(disc, jupiterExactOutRouteV2) ||
|
||||||
|
bytes.Equal(disc, jupiterSharedAccountsExactOutRouteV2) {
|
||||||
if len(instruction.Accounts) < 6 {
|
if len(instruction.Accounts) < 6 {
|
||||||
return nil, fmt.Errorf("not enough accounts for jupiter v6 v2 instruction")
|
return nil, fmt.Errorf("not enough accounts for jupiter v6 v2 instruction")
|
||||||
}
|
}
|
||||||
@@ -1414,6 +1622,12 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
destMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(instruction.Accounts[4]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
destMintOK = true
|
||||||
|
sourceMintOK = true
|
||||||
|
|
||||||
var (
|
var (
|
||||||
srcIdx uint8
|
srcIdx uint8
|
||||||
@@ -1436,14 +1650,11 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
baseMint, err := getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx]))
|
baseMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !sourceMint.Equals(baseMint) {
|
quoteMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx+1]))
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
quoteMint, err := getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx+1]))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1451,7 +1662,7 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if bytes.Equal(disc, jupiterSharedAccountsRoute) {
|
} else if bytes.Equal(disc, jupiterSharedAccountsRoute) || bytes.Equal(disc, jupiterSharedAccountsExactOutRoute) {
|
||||||
if len(instruction.Accounts) < 12 {
|
if len(instruction.Accounts) < 12 {
|
||||||
return nil, fmt.Errorf("not enough accounts for jupiter v6 jupiterSharedAccountsRoute instruction")
|
return nil, fmt.Errorf("not enough accounts for jupiter v6 jupiterSharedAccountsRoute instruction")
|
||||||
}
|
}
|
||||||
@@ -1459,6 +1670,12 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
destMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(instruction.Accounts[8]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
destMintOK = true
|
||||||
|
sourceMintOK = true
|
||||||
var (
|
var (
|
||||||
srcIdx uint8
|
srcIdx uint8
|
||||||
)
|
)
|
||||||
@@ -1480,15 +1697,12 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
baseMint, err := getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx]))
|
baseMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !sourceMint.Equals(baseMint) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
quoteMint, err := getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx+1]))
|
quoteMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx+1]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1517,35 +1731,72 @@ func parseJupiterV6Instruction(tx *versionedTransaction, instructionIndex int) (
|
|||||||
if srcIdx == 0 || srcIdx+1 >= uint8(len(accounts)) {
|
if srcIdx == 0 || srcIdx+1 >= uint8(len(accounts)) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
sourceMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx]))
|
baseMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
quoteMint, err := getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx+1]))
|
quoteMint, err = getStaticKey(tx.Message.StaticAccountKeys, int(accounts[srcIdx+1]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !quoteMint.Equals(solana.WrappedSol) {
|
if !quoteMint.Equals(solana.WrappedSol) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
sourceMint = baseMint
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasSell {
|
||||||
|
if sourceMintOK && !sourceMint.Equals(baseMint) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !sourceMintOK {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if !sourceMint.Equals(solana.WrappedSol) && !sourceMint.Equals(solana.SystemProgramID) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if destMintOK && !destMint.Equals(baseMint) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event := "sell"
|
||||||
|
exactSol := false
|
||||||
|
token0AmountUint64 := inputAmount
|
||||||
|
token1AmountUint64 := uint64(0)
|
||||||
|
if hasBuy {
|
||||||
|
event = "buy"
|
||||||
|
exactSol = !exactOut
|
||||||
|
token0AmountUint64 = buySwap.OutAmount
|
||||||
|
token1AmountUint64 = buySwap.InAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
token0Amount := decimal.Zero
|
||||||
|
if token0AmountUint64 > 0 {
|
||||||
|
token0Amount = formatTokenAmount(token0AmountUint64)
|
||||||
|
}
|
||||||
|
token1Amount := decimal.Zero
|
||||||
|
if token1AmountUint64 > 0 {
|
||||||
|
token1Amount = formatSolAmount(token1AmountUint64)
|
||||||
}
|
}
|
||||||
|
|
||||||
signal := &TxSignal{
|
signal := &TxSignal{
|
||||||
TxHash: tx.Signatures[0].String(),
|
TxHash: tx.Signatures[0].String(),
|
||||||
Maker: tx.Message.StaticAccountKeys[0].String(),
|
Maker: tx.Message.StaticAccountKeys[0].String(),
|
||||||
Token0Address: sourceMint.String(),
|
Token0Address: baseMint.String(),
|
||||||
Token1Address: wsolMint,
|
Token1Address: wsolMint,
|
||||||
Token0Amount: formatTokenAmount(inputAmount),
|
Token0Amount: token0Amount,
|
||||||
Token1Amount: decimal.Zero,
|
Token1Amount: token1Amount,
|
||||||
Program: "PumpAMM",
|
Program: "PumpAMM",
|
||||||
Event: "sell",
|
Event: event,
|
||||||
IsToken2022: false,
|
IsToken2022: false,
|
||||||
IsMayhemMode: false,
|
IsMayhemMode: false,
|
||||||
ExactSOL: false,
|
ExactSOL: exactSol,
|
||||||
Block: tx.Block,
|
Block: tx.Block,
|
||||||
Token0AmountUint64: inputAmount,
|
Token0AmountUint64: token0AmountUint64,
|
||||||
Token1AmountUint64: 0,
|
Token1AmountUint64: token1AmountUint64,
|
||||||
}
|
}
|
||||||
|
|
||||||
return signal, nil
|
return signal, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user