2 Commits

Author SHA1 Message Date
75c35f56f1 fix juo v6 pump swap percent 2026-02-17 19:13:12 +08:00
79859bc079 update dflow new action 2026-02-15 20:41:47 +08:00
4 changed files with 98 additions and 4 deletions

View File

@@ -72,6 +72,11 @@ const (
ActOpenPredictionsOrder
ActScorchSwap
ActIncludeAccount
ActDFLOWStabbleWeightedSwap
ActVertigoSwap
ActSetMinimumLegOutputs
ActSetMinimumLegPrices
)
// DynamicRouteV1CandidateAction tags
@@ -104,7 +109,7 @@ type dflowSwapParams struct {
// bytes to skip for Action variants; only PumpFun* actions are decoded.
func skipDflowAction(dec *bin.Decoder, tag uint8) (*pumpFunAction, error) {
switch tag {
case ActWhirlpoolsSwap, ActClearpoolsSwap, ActWhirlpoolsSwapV2:
case ActWhirlpoolsSwap, ActClearpoolsSwap, ActWhirlpoolsSwapV2, ActDFLOWStabbleWeightedSwap, ActVertigoSwap:
// amount u64 + bool + orchestrator_flags u8
return nil, dec.SkipBytes(8 + 1 + 1)
case ActRaydiumAmmSwap, ActLifinityV2Swap, ActObricV2Swap,
@@ -181,6 +186,19 @@ func skipDflowAction(dec *bin.Decoder, tag uint8) (*pumpFunAction, error) {
return nil, dec.SkipBytes(8 + 16 + 1)
case ActIncludeAccount:
return nil, nil
case ActSetMinimumLegOutputs:
ln, err := dec.ReadUint32(binary.LittleEndian)
if err != nil {
return nil, err
}
return nil, dec.SkipBytes(uint(8 * ln))
case ActSetMinimumLegPrices:
// Vec<(u64, u8)>; read length and skip the pairs
ln, err := dec.ReadUint32(binary.LittleEndian)
if err != nil {
return nil, err
}
return nil, dec.SkipBytes(uint(uint64(ln) * (8 + 1)))
default:
return nil, fmt.Errorf("unsupported action tag %d", tag)
}

View File

@@ -0,0 +1,61 @@
package shreder
import (
"encoding/hex"
"testing"
)
func TestDFlowDecodedSwapParams(t *testing.T) {
tests := []struct {
name string
hexData string
}{
{
name: "DFlow swap Test 0",
hexData: "f8c69e91e17587c806000000256cb411cd4dcea8c073833936254cc3a7a6f1bc3e1106af1fceaed1bf6d75184d8149476a66d1f0d4c23c177e81d73b8b11297c7f7d8a8d6e339939647915d8096cfcdd170000000093000000300300000000000000000000000000000000000000a84325c4000000002d0decfc36e0bc09000001197bcde00df80000000180130edffead0800000081711ebdc4000000002c013200",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
instrData, err := hex.DecodeString(tt.hexData)
if err != nil {
t.Fatalf("failed to decode hex string: %v", err)
return
}
//t.Logf("raw bytes: %x", instrData[8:])
args, err := decodeSwapParams(instrData[8:])
if err != nil {
t.Fatalf("failed to decode dflow arguments: %v", err)
return
}
t.Logf("decoded args: %+v", args)
})
}
}
func TestDFlowV2DecodedSwapParams(t *testing.T) {
tests := []struct {
name string
hexData string
}{
{
name: "DFlow swap 2 Test 0",
hexData: "414b3f4ceb5b5b880300000025427ee16eed91684faaad4a3f161acd31d92bbc3d1ba0e2ebdb4678448fd5a7aeade9c8b38e8755e811f3373a0056cd5647e4cc3510135f98e97cb03c046ade049d08de17000000007800000023f50a0000000000002e1bfe04000000000001c3e13700000000003601000005",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
instrData, err := hex.DecodeString(tt.hexData)
if err != nil {
t.Fatalf("failed to decode hex string: %v", err)
return
}
args, err := decodeSwap2Params(instrData[8:])
if err != nil {
t.Fatalf("failed to decode dflow arguments: %v", err)
return
}
t.Logf("decoded args: %+v", args)
})
}
}

View File

@@ -1119,9 +1119,11 @@ func pumpRoutePlanStatsV2(in uint64, out uint64, plan []RoutePlanStepV2, include
func parseJupiterPumpAmmRoute(tx VersionedTransaction, instruction Instructions, in uint64, out uint64, plan []RoutePlanStep) (*TxSignal, bool, error) {
var (
isBuy bool
isSell bool
count int
isBuy bool
isSell bool
count int
sellPercent uint8
buyPercent uint8
)
for _, step := range plan {
if !isInputIdx0(step.InputIdx) {
@@ -1130,9 +1132,11 @@ func parseJupiterPumpAmmRoute(tx VersionedTransaction, instruction Instructions,
if isPumpSwapSellKind(step.Swap.Kind) {
isSell = true
count++
sellPercent = step.Percent
} else if isPumpSwapBuyKind(step.Swap.Kind) {
isBuy = true
count++
buyPercent = step.Percent
}
}
if count == 0 {
@@ -1154,6 +1158,9 @@ func parseJupiterPumpAmmRoute(tx VersionedTransaction, instruction Instructions,
if in > 0 {
token0Amount = formatTokenAmount(in)
}
if sellPercent > 0 && sellPercent < 100 {
token0Amount = token0Amount.Mul(decimal.NewFromInt(int64(sellPercent))).Div(decimal.NewFromInt(100))
}
return &TxSignal{
TxHash: tx.Signatures[0].String(),
Maker: tx.StaticAccountKeys[0].String(),
@@ -1189,6 +1196,10 @@ func parseJupiterPumpAmmRoute(tx VersionedTransaction, instruction Instructions,
if in > 0 {
token1Amount = formatSolAmount(in)
}
if buyPercent > 0 && buyPercent < 100 {
token1Amount = token1Amount.Mul(decimal.NewFromInt(int64(buyPercent))).Div(decimal.NewFromInt(100))
token0Amount = token0Amount.Mul(decimal.NewFromInt(int64(buyPercent))).Div(decimal.NewFromInt(100))
}
return &TxSignal{
TxHash: tx.Signatures[0].String(),
Maker: tx.StaticAccountKeys[0].String(),

View File

@@ -67,6 +67,10 @@ func TestDecodeRouteArg(t *testing.T) {
name: "Jupiter V6 RouteArg Test 1",
hexData: "e517cb977ae3ad2a03000000646400017ab0b6c3d206f46577050000000c0000526401025f00640203bb628e2902000000338c430100000000320000",
},
{
name: "Jupiter V6 RouteArg Test 2",
hexData: "e517cb977ae3ad2a04000000642300024b00000000410002761acfb15ea9fdcd0501200204769358e96343759bf8014402046196591e1e020000f5bf6fe101000000d00700",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {