6 Commits

Author SHA1 Message Date
32ba6da171 chore: trim tip address 2026-03-18 12:20:37 +08:00
42631499c9 chore: remove 0slot tip addresses 2026-03-18 11:47:47 +08:00
9a37e57473 chore: update swqos fee address 2026-03-12 12:43:39 +08:00
thloyi
e981df5f4b [parser]: add maestro pumpamm 2026-03-11 14:03:25 +08:00
thloyi
c20e019b43 update jup enum 2026-03-03 14:25:46 +08:00
cachalots
c7be7cf4fd culimit 2026-02-27 16:45:57 +08:00
5 changed files with 295 additions and 26 deletions

View File

@@ -22,18 +22,8 @@ var SWQoSFeeAddresses = map[string]string{
"Ey2JEr8hDkgN8qKJGrLf2yFjRhW7rab99HVxwi5rcvJE": enum.SWQoSAgent0slot, "Ey2JEr8hDkgN8qKJGrLf2yFjRhW7rab99HVxwi5rcvJE": enum.SWQoSAgent0slot,
"4iUgjMT8q2hNZnLuhpqZ1QtiV8deFPy2ajvvjEpKKgsS": enum.SWQoSAgent0slot, "4iUgjMT8q2hNZnLuhpqZ1QtiV8deFPy2ajvvjEpKKgsS": enum.SWQoSAgent0slot,
"3Rz8uD83QsU8wKvZbgWAPvCNDU6Fy8TSZTMcPm3RB6zt": enum.SWQoSAgent0slot, "3Rz8uD83QsU8wKvZbgWAPvCNDU6Fy8TSZTMcPm3RB6zt": enum.SWQoSAgent0slot,
"DiTmWENJsHQdawVUUKnUXkconcpW4Jv52TnMWhkncF6t": enum.SWQoSAgent0slot,
"HRyRhQ86t3H4aAtgvHVpUJmw64BDrb61gRiKcdKUXs5c": enum.SWQoSAgent0slot,
"7y4whZmw388w1ggjToDLSBLv47drw5SUXcLk6jtmwixd": enum.SWQoSAgent0slot,
"J9BMEWFbCBEjtQ1fG5Lo9kouX1HfrKQxeUxetwXrifBw": enum.SWQoSAgent0slot,
"8U1JPQh3mVQ4F5jwRdFTBzvNRQaYFQppHQYoH38DJGSQ": enum.SWQoSAgent0slot,
"Eb2KpSC8uMt9GmzyAEm5Eb1AAAgTjRaXWFjKyFXHZxF3": enum.SWQoSAgent0slot,
"FCjUJZ1qozm1e8romw216qyfQMaaWKxWsuySnumVCCNe": enum.SWQoSAgent0slot,
"ENxTEjSQ1YabmUpXAdCgevnHQ9MHdLv8tzFiuiYJqa13": enum.SWQoSAgent0slot,
"6rYLG55Q9RpsPGvqdPNJs4z5WTxJVatMB8zV3WJhs5EK": enum.SWQoSAgent0slot,
"Cix2bHfqPcKcM233mzxbLk14kSggUUiz2A87fJtGivXr": enum.SWQoSAgent0slot,
"HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY": enum.SWQoSAgentBlocxRoute, "HWEoBxYs7ssKuudEjzjmpfJVX7Dvi7wescFsVx2L5yoY": enum.SWQoSAgentBlocxRoute,
"HZTmLyC683y74TW3HtGbNX5orxjm2sPuZBEYwwSgAM8v": enum.SWQoSAgentBlocxRoute, "95cfoy472fcQHaw4tPGBTKpn6ZQnfEPfBgDQx6gcRmRg": enum.SWQoSAgentBlocxRoute,
"FogxVNs6Mm2w9rnGL1vkARSwJxvLE8mujTv3LK8RnUhF": enum.SWQoSAgentBlocxRoute, "FogxVNs6Mm2w9rnGL1vkARSwJxvLE8mujTv3LK8RnUhF": enum.SWQoSAgentBlocxRoute,
"3UQUKjhMKaY2S6bjcQD6yHB7utcZt5bfarRCmctpRtUd": enum.SWQoSAgentBlocxRoute, "3UQUKjhMKaY2S6bjcQD6yHB7utcZt5bfarRCmctpRtUd": enum.SWQoSAgentBlocxRoute,
"TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq": enum.SWQoSAgentNozomi, "TEMPaMeCRFAS9EKF53Jd6KpHxgL47uWLcpFArU1Fanq": enum.SWQoSAgentNozomi,
@@ -77,13 +67,6 @@ var SWQoSFeeAddresses = map[string]string{
"node1PUber6SFmSQgvf2ECmXsHP5o3boRSGhvJyPMX1": enum.SWQoSAgentNode1, "node1PUber6SFmSQgvf2ECmXsHP5o3boRSGhvJyPMX1": enum.SWQoSAgentNode1,
"node1AyMbeqiVN6eoQzEAwCA6Pk826hrdqdAHR7cdJ3": enum.SWQoSAgentNode1, "node1AyMbeqiVN6eoQzEAwCA6Pk826hrdqdAHR7cdJ3": enum.SWQoSAgentNode1,
"node1YtWCoTwwVYTFLfS19zquRQzYX332hs1HEuRBjC": enum.SWQoSAgentNode1, "node1YtWCoTwwVYTFLfS19zquRQzYX332hs1HEuRBjC": enum.SWQoSAgentNode1,
"node1EoLojAvoUmyDytcvgdXs6GPtY3zpQXPCRVncEA": enum.SWQoSAgentNode1,
"node1CVxtFas2Pw5Vcf86Pq89Hqx4jveo1ntY7ARFMK": enum.SWQoSAgentNode1,
"node1E3hguapYA18HCpEEkRHQmLNiyv9pdfE9s2zo5X": enum.SWQoSAgentNode1,
"node1zrVjcY2XB3Au8qYj5MxjbNfGu3baHaqZMkPM7Z": enum.SWQoSAgentNode1,
"node1FdMPnJBN7QTuhzNw3VS823nxFuDTizrrbcEqzp": enum.SWQoSAgentNode1,
"node1VwH169UqyJHr5MYCH3EBuwrdvn5KHXAkhEEfav": enum.SWQoSAgentNode1,
"node1L7Xat2tSkRNNi6TSuUScMYfj64ovhr2aceJm9g": enum.SWQoSAgentNode1,
"FLasHstqx11M8W56zrSEqkCyhMCCpr6ze6Mjdvqope5s": enum.SWQoSAgentFlashBlock, "FLasHstqx11M8W56zrSEqkCyhMCCpr6ze6Mjdvqope5s": enum.SWQoSAgentFlashBlock,
"FLasHXTqrbNvpWFB6grN47HGZfK6pze9HLNTgbukfPSk": enum.SWQoSAgentFlashBlock, "FLasHXTqrbNvpWFB6grN47HGZfK6pze9HLNTgbukfPSk": enum.SWQoSAgentFlashBlock,
"FLashhsorBmM9dLpuq6qATawcpqk1Y2aqaZfkd48iT3W": enum.SWQoSAgentFlashBlock, "FLashhsorBmM9dLpuq6qATawcpqk1Y2aqaZfkd48iT3W": enum.SWQoSAgentFlashBlock,
@@ -108,6 +91,15 @@ var SWQoSFeeAddresses = map[string]string{
"BnGKHAC386n4Qmv9xtpBVbRaUTKixjBe3oagkPFKtoy6": enum.SWQoSAgentBlockRazor, "BnGKHAC386n4Qmv9xtpBVbRaUTKixjBe3oagkPFKtoy6": enum.SWQoSAgentBlockRazor,
"Dd7K2Fp7AtoN8xCghKDRmyqr5U169t48Tw5fEd3wT9mq": enum.SWQoSAgentBlockRazor, "Dd7K2Fp7AtoN8xCghKDRmyqr5U169t48Tw5fEd3wT9mq": enum.SWQoSAgentBlockRazor,
"AP6qExwrbRgBAVaehg4b5xHENX815sMabtBzUzVB4v8S": enum.SWQoSAgentBlockRazor, "AP6qExwrbRgBAVaehg4b5xHENX815sMabtBzUzVB4v8S": enum.SWQoSAgentBlockRazor,
"soyas4s6L8KWZ8rsSk1mF3d1mQScoTGGAgjk98bF8nP": enum.SWQoSAgentSoyas,
"soyascXFW5wEEYiwfEmHy2pNwomqzvggJosGVD6TJdY": enum.SWQoSAgentSoyas,
"soyasDBdKjADwPz3xk82U3TNPRDKEWJj7wWLajNHZ1L": enum.SWQoSAgentSoyas,
"soyasE2abjBAynmHbGWgEwk4ctBy7JMTUCNrMbjcnyH": enum.SWQoSAgentSoyas,
"ste11JV3MLMM7x7EJUM2sXcJC1H7F4jBLnP9a9PG8PH": enum.SWQoSAgentStellium,
"ste11MWPjXCRfQryCshzi86SGhuXjF4Lv6xMXD2AoSt": enum.SWQoSAgentStellium,
"ste11p5x8tJ53H1NbNQsRBg1YNRd4GcVpxtDw8PBpmb": enum.SWQoSAgentStellium,
"ste11p7e2KLYou5bwtt35H7BM6uMdo4pvioGjJXKFcN": enum.SWQoSAgentStellium,
"ste11TMV68LMi1BguM4RQujtbNCZvf1sjsASpqgAvSX": enum.SWQoSAgentStellium,
"astrazznxsGUhWShqgNtAdfrzP2G83DzcWVJDxwV9bF": enum.SWQoSAgentAstralane, "astrazznxsGUhWShqgNtAdfrzP2G83DzcWVJDxwV9bF": enum.SWQoSAgentAstralane,
"astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm": enum.SWQoSAgentAstralane, "astra4uejePWneqNaJKuFFA8oonqCE1sqF6b45kDMZm": enum.SWQoSAgentAstralane,
"astra9xWY93QyfG6yM8zwsKsRodscjQ2uU2HKNL5prk": enum.SWQoSAgentAstralane, "astra9xWY93QyfG6yM8zwsKsRodscjQ2uU2HKNL5prk": enum.SWQoSAgentAstralane,
@@ -116,10 +108,12 @@ var SWQoSFeeAddresses = map[string]string{
"astraubkDw81n4LuutzSQ8uzHCv4BhPVhfvTcYv8SKC": enum.SWQoSAgentAstralane, "astraubkDw81n4LuutzSQ8uzHCv4BhPVhfvTcYv8SKC": enum.SWQoSAgentAstralane,
"astraZW5GLFefxNPAatceHhYjfA1ciq9gvfEg2S47xk": enum.SWQoSAgentAstralane, "astraZW5GLFefxNPAatceHhYjfA1ciq9gvfEg2S47xk": enum.SWQoSAgentAstralane,
"astrawVNP4xDBKT7rAdxrLYiTSTdqtUr63fSMduivXK": enum.SWQoSAgentAstralane, "astrawVNP4xDBKT7rAdxrLYiTSTdqtUr63fSMduivXK": enum.SWQoSAgentAstralane,
"ste11JV3MLMM7x7EJUM2sXcJC1H7F4jBLnP9a9PG8PH": enum.SWQoSAgentStellium, "FAST3dMFZvESiEipBvLSiXq3QCV51o3xuoHScqRU6cB6": enum.SWQoSAgentFast,
"ste11MWPjXCRfQryCshzi86SGhuXjF4Lv6xMXD2AoSt": enum.SWQoSAgentStellium, "FASTCKnwwY6iL3CknRgg3Zqir7jeagDDhxSnBQQy5a1C": enum.SWQoSAgentFast,
"ste11p5x8tJ53H1NbNQsRBg1YNRd4GcVpxtDw8PBpmb": enum.SWQoSAgentStellium, "FASTHPW6akdGh9PFSdhMTbCuGkCSX7LsUjjnaB2RTQ4v": enum.SWQoSAgentFast,
"ste11p7e2KLYou5bwtt35H7BM6uMdo4pvioGjJXKFcN": enum.SWQoSAgentStellium, "FASTKL1AamNKrwnvbKwo4PU8434BBdqVrTtugM6oDU71": enum.SWQoSAgentFast,
"ste11TMV68LMi1BguM4RQujtbNCZvf1sjsASpqgAvSX": enum.SWQoSAgentStellium, "FASTPB76TxKPMZ7Q29m8v4zJn8gUjbWyvTEQaaxhwN7M": enum.SWQoSAgentFast,
"soyas4s6L8KWZ8rsSk1mF3d1mQScoTGGAgjk98bF8nP": enum.SWQoSAgentSoyas, "FASTYKWXRfAoty7SQCM1mGVrmPUyyNcF4tc3DUkLDAu9": enum.SWQoSAgentFast,
"FASTYmSidNfLwdwiQEhCTtzghxEtaipeNSDSwh9xDPs3": enum.SWQoSAgentFast,
"FASTs6ctgbsuZegMzUs4DPUYhRSZUPCjgCVnttHbpQAp": enum.SWQoSAgentFast,
} }

View File

@@ -160,6 +160,8 @@ const (
Scorch Scorch
VaultLiquidUnstake VaultLiquidUnstake
XOrca XOrca
Quantum
WhaleStreetV2
) )
var swapKindNames = [122]string{"Saber", "SaberAddDecimalsDeposit", "SaberAddDecimalsWithdraw", "TokenSwap", "Sencha", "Step", "Cropper", var swapKindNames = [122]string{"Saber", "SaberAddDecimalsDeposit", "SaberAddDecimalsWithdraw", "TokenSwap", "Sencha", "Step", "Cropper",
@@ -333,8 +335,20 @@ func decodeSwap(dec *bin.Decoder) (Swap, error) {
case RaydiumLaunchlabBuy, RaydiumLaunchlabSell: case RaydiumLaunchlabBuy, RaydiumLaunchlabSell:
return out, skipU64() return out, skipU64()
// -------- Side(u8) payload -------- // -------- Side(u8) payload --------
case Serum, Aldrin, AldrinV2, Dradex, Openbook, Phoenix, OpenBookV2, TokenMill, Plasma, TesseraV, Futarchy, WhaleStreet, Manifest: case Serum, Aldrin, AldrinV2, Dradex, Openbook, Phoenix, OpenBookV2, TokenMill, Plasma, TesseraV, Futarchy,
WhaleStreet, Manifest, Quantum:
return out, skipU8() return out, skipU8()
case WhaleStreetV2:
if err := skipU8(); err != nil {
return Swap{}, err
}
if err := skipU64(); err != nil {
return Swap{}, err
}
if err := skipU64(); err != nil {
return Swap{}, err
}
return out, nil
// -------- MeteoraDlmmSwapV2: RemainingAccountsInfo -------- // -------- MeteoraDlmmSwapV2: RemainingAccountsInfo --------
case MeteoraDlmmSwapV2: case MeteoraDlmmSwapV2:
return out, skipRemaining() return out, skipRemaining()

View File

@@ -0,0 +1,257 @@
package shreder
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/gagliardetto/solana-go"
)
var (
maestroProgramId = solana.MustPublicKeyFromBase58("MaestroAAe9ge5HTc64VbBQZ6fP77pwvrhM8i1XWSAx")
maestroMultiSwap2Discriminator = [8]byte{132, 9, 212, 45, 39, 113, 215, 54}
)
type MaestroMultiSwap2Route struct {
DexID uint8
RouteKeyIdx uint8
}
// MaestroMultiSwap2Args is the decoded payload of multi_swap2 instruction.
// Payload layout (without 8-byte discriminator):
// amount_in(u64), min_amount_out(u64), route0_weight(u16), route_len(u32),
// routes(route_len * {dex_id(u8), reserved(u8), route_key_idx(u8)}), route_family(u8), route_flags(u8)
type MaestroMultiSwap2Args struct {
HasDiscriminator bool
AmountIn uint64
MinAmountOut uint64
SlippageBps uint16
RouteLen uint32
Routes []MaestroMultiSwap2Route
RouteFamily uint8
RouteFlags uint8
Extra []byte
}
// decodeMaestroMultiSwap2Args decodes instruction bytes with or without the 8-byte multi_swap2 discriminator.
func decodeMaestroMultiSwap2Args(data []byte) (*MaestroMultiSwap2Args, error) {
if len(data) == 0 {
return nil, fmt.Errorf("empty data")
}
payload := data
out := &MaestroMultiSwap2Args{}
if len(data) >= len(maestroMultiSwap2Discriminator) && bytes.Equal(data[:8], maestroMultiSwap2Discriminator[:]) {
out.HasDiscriminator = true
payload = data[8:]
}
const minPayloadLen = 24 // fixed fields + route_family + route_flags when route_len==0
if len(payload) < minPayloadLen {
return nil, fmt.Errorf("payload too short: got %d, need at least %d", len(payload), minPayloadLen)
}
out.AmountIn = binary.LittleEndian.Uint64(payload[0:8])
out.MinAmountOut = binary.LittleEndian.Uint64(payload[8:16])
out.SlippageBps = binary.LittleEndian.Uint16(payload[16:18])
out.RouteLen = binary.LittleEndian.Uint32(payload[18:22])
needed := uint64(minPayloadLen) + uint64(out.RouteLen)*3
if needed > uint64(len(payload)) {
return nil, fmt.Errorf("payload too short for routes: got %d, need %d (route_len=%d)", len(payload), needed, out.RouteLen)
}
offset := 22
out.Routes = make([]MaestroMultiSwap2Route, 0, out.RouteLen)
for i := uint32(0); i < out.RouteLen; i++ {
route := MaestroMultiSwap2Route{
DexID: payload[offset],
RouteKeyIdx: payload[offset+2],
}
out.Routes = append(out.Routes, route)
offset += 3
}
out.RouteFamily = payload[offset]
out.RouteFlags = payload[offset+1]
offset += 2
if len(payload) > offset {
out.Extra = append([]byte(nil), payload[offset:]...)
}
return out, nil
}
// maestroMultiSwap2DexName maps observed dex ids from MultiSwap2 routes.
func maestroMultiSwap2DexName(dexID uint8) string {
switch dexID {
case 0:
return "RaydiumV4"
case 1:
return "MeteoraDLMM"
case 3:
return "RaydiumLaunchLab"
case 4:
return "PumpAMM"
case 5:
return "RaydiumCPMM"
case 6:
return "MeteoraAmmV2"
case 7:
return "RaydiumCLMM"
case 8:
return "OrcaWhirPool"
case 9:
return "MeteoraPools"
case 10:
return "MeteoraDynamicBondingCurve"
default:
return fmt.Sprintf("Unknown(%d)", dexID)
}
}
func parseMaestroInstruction(tx VersionedTransaction, idx int) (TxSignalBatch, error) {
if idx >= len(tx.Instructions) {
return nil, fmt.Errorf("instruction index out of bounds")
}
ix := tx.Instructions[idx]
if len(ix.Data) < 8 {
return nil, nil
}
return parseMaestroInstructionDataAndAccounts(tx, ix.Data, ix.Accounts)
}
func parseMaestroInstructionDataAndAccounts(tx VersionedTransaction, ixData []byte, ixAccounts []uint8) (TxSignalBatch, error) {
args, err := decodeMaestroMultiSwap2Args(ixData)
if err != nil {
return nil, nil
}
// only decode pump amm
if len(args.Routes) != 1 {
return nil, nil
}
if args.Routes[0].DexID != 4 {
return nil, nil
}
var (
event string
token0Amount uint64
token1Amount uint64
// pool solana.PublicKey
baseMint solana.PublicKey
quoteMint solana.PublicKey
)
routeFlag := args.Routes[0].RouteKeyIdx
if routeFlag == 101 || routeFlag == 97 {
event = "buy"
token0Amount = args.MinAmountOut
token1Amount = args.AmountIn
} else if routeFlag == 65 || routeFlag == 71 {
event = "sell"
token0Amount = args.AmountIn
token1Amount = args.MinAmountOut
} else {
return nil, nil
}
if routeFlag == 101 || routeFlag == 71 {
if len(ixAccounts) < 22 {
return nil, nil
}
token2022, err := tx.GetAccount(int(ixAccounts[6]))
if err != nil {
return nil, err
}
if !token2022.Equals(solana.Token2022ProgramID) {
return nil, nil
}
//pool, err = tx.GetAccount(int(ixAccounts[10]))
if event == "buy" {
quoteMint, err = tx.GetAccount(int(ixAccounts[9]))
if err != nil {
return nil, err
}
baseMint, err = tx.GetAccount(int(ixAccounts[21]))
if err != nil {
return nil, err
}
} else {
baseMint, err = tx.GetAccount(int(ixAccounts[9]))
if err != nil {
return nil, err
}
quoteMint, err = tx.GetAccount(int(ixAccounts[21]))
if err != nil {
return nil, err
}
}
} else if routeFlag == 97 || routeFlag == 65 {
if len(ixAccounts) < 21 {
return nil, nil
}
tokenPro, err := tx.GetAccount(int(ixAccounts[5]))
if err != nil {
return nil, err
}
if !tokenPro.Equals(solana.TokenProgramID) {
return nil, nil
}
//pool, err = tx.GetAccount(int(ixAccounts[9]))
if event == "buy" {
quoteMint, err = tx.GetAccount(int(ixAccounts[8]))
if err != nil {
return nil, err
}
baseMint, err = tx.GetAccount(int(ixAccounts[20]))
if err != nil {
return nil, err
}
} else {
baseMint, err = tx.GetAccount(int(ixAccounts[8]))
if err != nil {
return nil, err
}
quoteMint, err = tx.GetAccount(int(ixAccounts[20]))
if err != nil {
return nil, err
}
}
}
if !quoteMint.Equals(wrappedSOL) {
return nil, nil
}
return TxSignalBatch{
&TxSignal{
TxHash: tx.Signatures[0].String(),
Maker: tx.StaticAccountKeys[0].String(),
Token0Address: baseMint.String(),
Token1Address: wsolMint,
Token0Amount: formatTokenAmount(token0Amount),
Token1Amount: formatTokenAmount(token1Amount),
Event: event,
Program: "PumpAMM",
IsProcessed: false,
IsToken2022: false,
IsMayhemMode: false,
ExactSOL: event == "buy",
Token0AmountUint64: token0Amount,
Token1AmountUint64: token1Amount,
},
}, nil
}

View File

@@ -48,6 +48,7 @@ type TxSignal struct {
CULimit uint32 `json:"cu_limit"` CULimit uint32 `json:"cu_limit"`
SWQoSAgent string `json:"swqos_agent"` SWQoSAgent string `json:"swqos_agent"`
SWQoSTips decimal.Decimal `json:"swqos_tips"` SWQoSTips decimal.Decimal `json:"swqos_tips"`
TableCnt int `json:"table_cnt"`
ExactSOL bool `json:"exact_in"` ExactSOL bool `json:"exact_in"`

View File

@@ -76,6 +76,7 @@ var (
dlmmProgramID: {parseDlmmInstruction, "dlmm"}, dlmmProgramID: {parseDlmmInstruction, "dlmm"},
dbotProgramID: {parseDbotInstruction, "dbot"}, dbotProgramID: {parseDbotInstruction, "dbot"},
tradewizProgramID: {parseTradewizInstruction, "tradewiz"}, tradewizProgramID: {parseTradewizInstruction, "tradewiz"},
maestroProgramId: {parseMaestroInstruction, "maestro"},
} }
) )
@@ -182,7 +183,8 @@ func ParseTransactionForEntries(ctx context.Context, slot uint64, entriesReader
} }
func ParseTransactionWithHandler(ctx context.Context, versioned VersionedTransaction, loader *AddressTables, parsed chan<- TxSignal, handlers map[solana.PublicKey]Handler) { func ParseTransactionWithHandler(ctx context.Context, versioned VersionedTransaction, loader *AddressTables, parsed chan<- TxSignal, handlers map[solana.PublicKey]Handler) {
if loader != nil && len(versioned.AddressTableLookups) > 0 { tableCnt := len(versioned.AddressTableLookups)
if loader != nil && tableCnt > 0 {
lookupTableOk := true lookupTableOk := true
for _, lookups := range versioned.AddressTableLookups { for _, lookups := range versioned.AddressTableLookups {
lookupTableOk = loader.FillToTx(&versioned, lookups.AccountKey, lookups.WritableIndexes) lookupTableOk = loader.FillToTx(&versioned, lookups.AccountKey, lookups.WritableIndexes)
@@ -266,6 +268,7 @@ func ParseTransactionWithHandler(ctx context.Context, versioned VersionedTransac
one.CULimit = cuLimit one.CULimit = cuLimit
one.SWQoSAgent = swqosAgent one.SWQoSAgent = swqosAgent
one.SWQoSTips = swqosTips one.SWQoSTips = swqosTips
one.TableCnt = tableCnt
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return