package shreder import ( "bytes" "encoding/binary" "fmt" "github.com/gagliardetto/solana-go" "github.com/shopspring/decimal" ) // For Metaora dlmm var dlmmProgramID = solana.MustPublicKeyFromBase58("LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo") var ( dlmmSwapIX = []byte{248, 198, 158, 145, 225, 117, 135, 200} dlmmSwap2IX = []byte{65, 75, 63, 76, 235, 91, 91, 136} dlmmSwapExactOutIX = []byte{250, 73, 101, 33, 38, 207, 75, 184} dlmmSwapExactOut2IX = []byte{43, 215, 247, 132, 137, 60, 243, 81} dlmmSwapPriceImpactIX = []byte{56, 173, 230, 208, 173, 228, 156, 205} dlmmSwapPriceImpact2IX = []byte{74, 98, 192, 214, 177, 51, 75, 51} ) type dlmmParsedArgs struct { AmountIn uint64 AmountOut uint64 ExactIn bool ExactOut bool ActiveBin int32 MaxPriceImpactBps uint16 } func dlmmTokenOrder(tokenX, tokenY solana.PublicKey) (solana.PublicKey, solana.PublicKey) { switch { case tokenX.Equals(solana.WrappedSol): return tokenY, tokenX case tokenY.Equals(solana.WrappedSol): return tokenX, tokenY default: return tokenX, tokenY } } func parseDlmmSwapArgs(disc []byte, payload []byte) (*dlmmParsedArgs, error) { switch { case bytes.Equal(disc, dlmmSwapIX), bytes.Equal(disc, dlmmSwap2IX): if len(payload) < 16 { return nil, fmt.Errorf("data too short for dlmm swap args, len=%d", len(payload)) } return &dlmmParsedArgs{ AmountIn: binary.LittleEndian.Uint64(payload[0:8]), AmountOut: binary.LittleEndian.Uint64(payload[8:16]), ExactIn: true, }, nil case bytes.Equal(disc, dlmmSwapExactOutIX), bytes.Equal(disc, dlmmSwapExactOut2IX): if len(payload) < 16 { return nil, fmt.Errorf("data too short for dlmm swap exact out args, len=%d", len(payload)) } return &dlmmParsedArgs{ AmountIn: binary.LittleEndian.Uint64(payload[0:8]), AmountOut: binary.LittleEndian.Uint64(payload[8:16]), ExactOut: true, }, nil case bytes.Equal(disc, dlmmSwapPriceImpactIX), bytes.Equal(disc, dlmmSwapPriceImpact2IX): if len(payload) < 11 { return nil, fmt.Errorf("data too short for dlmm swap with price impact args, len=%d", len(payload)) } amountIn := binary.LittleEndian.Uint64(payload[0:8]) idx := 8 if len(payload) < idx+1 { return nil, fmt.Errorf("data too short for dlmm swap with price impact args, len=%d", len(payload)) } activeBinTag := payload[idx] idx++ var activeBin int32 if activeBinTag == 1 { if len(payload) < idx+4 { return nil, fmt.Errorf("data too short for dlmm swap with price impact args, len=%d", len(payload)) } activeBin = int32(binary.LittleEndian.Uint32(payload[idx : idx+4])) idx += 4 } else if activeBinTag != 0 { return nil, fmt.Errorf("invalid active_id tag %d", activeBinTag) } if len(payload) < idx+2 { return nil, fmt.Errorf("data too short for dlmm swap with price impact args, len=%d", len(payload)) } return &dlmmParsedArgs{ AmountIn: amountIn, ExactIn: true, ActiveBin: activeBin, MaxPriceImpactBps: binary.LittleEndian.Uint16(payload[idx : idx+2]), }, nil default: return nil, nil } } func parseDlmmInstruction(tx VersionedTransaction, instructionIndex int) (TxSignalBatch, error) { if instructionIndex >= len(tx.Instructions) { return nil, fmt.Errorf("instruction index out of bounds") } instruction := tx.Instructions[instructionIndex] if len(instruction.Data) < 8 { return nil, fmt.Errorf("data is empty") } if len(instruction.Accounts) < 13 { return nil, nil // fmt.Errorf("accounts too short") } disc := instruction.Data[:8] payload := instruction.Data[8:] args, err := parseDlmmSwapArgs(disc, payload) if err != nil { return nil, err } if args == nil { return nil, nil } userTokenIn, err := tx.GetAccount(int(instruction.Accounts[4])) if err != nil { return nil, err } lbPair, err := tx.GetAccount(int(instruction.Accounts[0])) if err != nil { return nil, err } userTokenOut, err := tx.GetAccount(int(instruction.Accounts[5])) if err != nil { return nil, err } tokenX, err := tx.GetAccount(int(instruction.Accounts[6])) if err != nil { return nil, err } tokenY, err := tx.GetAccount(int(instruction.Accounts[7])) if err != nil { return nil, err } user, err := tx.GetAccount(int(instruction.Accounts[10])) if err != nil { return nil, err } tokenXProgram, err := tx.GetAccount(int(instruction.Accounts[11])) if err != nil { return nil, err } tokenYProgram, err := tx.GetAccount(int(instruction.Accounts[12])) if err != nil { return nil, err } token0Mint, token1Mint := dlmmTokenOrder(tokenX, tokenY) var ( token0AmountUint64 uint64 token1AmountUint64 uint64 ) if !tokenX.Equals(solana.WrappedSol) && !tokenY.Equals(solana.WrappedSol) { return nil, nil } wsolProgram := tokenXProgram if tokenY.Equals(solana.WrappedSol) { wsolProgram = tokenYProgram } wsolAta, _, err := findAssociatedTokenAddressWithTokenProgram(user, solana.WrappedSol, wsolProgram) if err != nil { return nil, nil } wsolIn := userTokenIn.Equals(wsolAta) wsolOut := userTokenOut.Equals(wsolAta) if !wsolIn && !wsolOut { return nil, nil } event := "sell" if wsolIn { event = "buy" } exactSol := (args.ExactIn && wsolIn) || (args.ExactOut && wsolOut) if wsolIn { if args.ExactIn { token1AmountUint64 = args.AmountIn } if args.ExactOut { token0AmountUint64 = args.AmountOut } } else { if args.ExactOut { token1AmountUint64 = args.AmountOut } if args.ExactIn { token0AmountUint64 = args.AmountIn } } token0Amount := formatTokenAmount(token0AmountUint64) if token0Mint.Equals(solana.WrappedSol) { token0Amount = formatSolAmount(token0AmountUint64) } token1Amount := decimal.Zero if token1AmountUint64 > 0 { if token1Mint.Equals(solana.WrappedSol) { token1Amount = formatSolAmount(token1AmountUint64) } else { token1Amount = formatTokenAmount(token1AmountUint64) } } return TxSignalBatch{&TxSignal{ TxHash: tx.Signatures[0].String(), Label: "dlmm", Maker: user.String(), Token0Address: token0Mint.String(), Token1Address: token1Mint.String(), Token0Amount: token0Amount, Token1Amount: token1Amount, Program: "MeteoraDLMM", Event: event, IsToken2022: false, IsMayhemMode: false, ExactSOL: exactSol, ActiveBin: args.ActiveBin, MaxPriceImpactBps: args.MaxPriceImpactBps, LbPairAddress: lbPair.String(), Block: tx.Block, Token0AmountUint64: token0AmountUint64, Token1AmountUint64: token1AmountUint64, }}, nil }