跳轉至

Sandwich Detector

介紹

Sandwich Detector為項目方(如錢包、DEX和Trading Bot)提供Solana交易的三明治攻擊監測服務,用戶可基於gRPC實時訂閱Solana上的三明治攻擊交易信息,訂閱端點: solana.sandwich-detector.blockrazor.me:443

訂閱計劃

Tier 4Tier 3Tier 2Tier 1Tier 0
Sandwich Detector----支持

Sandwich Detector服務會向訂閱Tier 0計劃的项目方(如錢包、DEX和Trading Bot)開放白名單,白名單用戶可實時訂閱Solana交易的三明治攻擊交易信息,請在訂閱Tier 0計劃後與我們聯繫

請求參數

参数必選格式示例备注
signerString"6yf14f……iwPZ3V"通過被攻擊交易的發起者賬戶地址篩選三明治交易信息
relevantProgramIdString"CAMMCz……KgrWqK"通過被攻擊交易交互的programId篩選三明治交易信息

請求示例

{% tabs %} {% tab title="grpccurl" %}

# without filter
grpcurl -plaintext=false -import-path /path/to/proto -proto solstream.proto -d ''  solana.sandwich-detector.blockrazor.me:443 solstream.TxStreamService/SubscribeTxStream
# with filter
grpcurl -plaintext=false -import-path /path/to/proto -proto solstream.proto -d '{"relevantProgramId":"aa..bb"}'  solana.sandwich-detector.blockrazor.me:443 solstream.TxStreamService/SubscribeTxStream

{% endtab %}

{% tab title="Go" %}

package main

import (
    "context"
    "crypto/tls"
    "log"

    pb "solstream/proto/solstream"

    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

func main() {
    for {
        conn, err := grpc.Dial(
            "solana.sandwich-detector.blockrazor.me:443",
            grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
            grpc.WithContextDialer(func(ctx context.Context, addr string) (net.Conn, error) { //use ipv4
                d := net.Dialer{DualStack: false}
                return d.DialContext(ctx, "tcp4", addr)
            }),
        )
        if err != nil {
            log.Printf("Failed to connect: %v.\n", err)
            continue
        }

        client := pb.NewTxStreamServiceClient(conn)
        stream, err := client.SubscribeTxStream(context.Background(), &pb.TxFilter{
            // Empty for no filter
            Signer:            "",
            RelevantProgramId: "",
        })
        if err != nil {
            log.Printf("Error subscribing to stream: %v.\n", err)
            conn.Close()
            continue
        }

        log.Println("Successfully subscribed to the stream.")

        for {
            resp, err := stream.Recv()
            if err != nil {
                log.Printf("Error receiving stream data: %v. Reconnecting...\n", err)
                conn.Close()
                break
            }
            log.Println(resp)

        }
    }

}

{% endtab %} {% endtabs %}

Proto

// solstream.proto
syntax = "proto3";

package solstream;

option go_package = "proto/solstream";

service TxStreamService {
  rpc SubscribeTxStream(TxFilter) returns (stream TxStreamResponse);
}

message TxFilter {
  string signer = 1;            // (optional) signer of victim tx to filter
  string relevantProgramId = 2; // (optional) interacted program id of victim tx to filter. For example, programId of some router
}

message TxStreamResponse {
  uint64 slot = 1;                 // slot of sandwich txs
  repeated string txs = 2;         // all sandwich tx signatures
  string victimtx = 3;             // victim tx signature
  repeated string attackertxs = 4; // frontrun and backrun tx signature
  string signer = 5;               // signaer of victim tx

  bool heartbeat = 6;              // if this resp is heartbeat, to keep stream alive if no sandwich data available
}

返回示例

{
  "slot": "330748316",
  "txs": [
    "3gDiqwyYnqLtBrkdF5Y6RJiattctYjKu2NfjcAupDBRkhodh9a22XjPYYdhf83FpGUnBe2g1oeLxfpNYG8QyCrUt",
    "4joomCxakJxi9vhJ6mRuFStyiUyetaB2X1HMj4g3VUSTMQkPgMTAZ7NaLNMejvfu9zdp7gXp2fM5UEgVK5PohVrP",
    "4QgGbPiaNyhgMrkeFrNjZaPNDQTvXqc1THVQJXvbN26gBt8GxQikBzk5fiQyjvffLt8PJUGNw21GU55iErmQcGkC"
  ],
  "victimtx": "4joomCxakJxi9vhJ6mRuFStyiUyetaB2X1HMj4g3VUSTMQkPgMTAZ7NaLNMejvfu9zdp7gXp2fM5UEgVK5PohVrP",
  "attackertxs": [
    "3gDiqwyYnqLtBrkdF5Y6RJiattctYjKu2NfjcAupDBRkhodh9a22XjPYYdhf83FpGUnBe2g1oeLxfpNYG8QyCrUt",
    "4QgGbPiaNyhgMrkeFrNjZaPNDQTvXqc1THVQJXvbN26gBt8GxQikBzk5fiQyjvffLt8PJUGNw21GU55iErmQcGkC"
  ],
  "signer": "Ejhath43fHYtWLbSMfVHCL8eJiLkV22K6w1Ni5xzXofX" // signer of victim tx
}