# Send Bundle

## 接口說明

本接口用於接收用戶提交的bundle，方法名為`eth_sendBundle`。&#x20;

BlockRazor MEV服務的區塊構建算法傾向於向BlockRazor Builder EOA轉賬原生代幣（BNB）數量更多的bundle，當前BlockRazor Builder EOA地址為0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20。\
bundle中交易的gas price需不小於BSC Validator要求的最低標準（當前為0.1 gwei）。

對於Tier 2 / Tier 1 / Tier0用戶，可以在bundle中包含0 gwei的交易，但bundle中交易（public mempool中的交易除外）的平均gasPrice仍需不小於0.1 gwei。



## 流控說明

<table><thead><tr><th width="212"></th><th width="132.26953125">Tier 4</th><th>Tier 3</th><th width="135.984375">Tier 2</th><th>Tier 1</th><th>Tier0</th></tr></thead><tbody><tr><td>BPS</td><td>不限</td><td>不限</td><td>不限</td><td>不限</td><td>不限</td></tr><tr><td>每區塊可接受bundle數</td><td>不限</td><td>不限</td><td>不限</td><td>不限</td><td>不限</td></tr><tr><td>bundle包含0 gwei交易</td><td>-</td><td>-</td><td>支持</td><td>支持</td><td>支持</td></tr><tr><td>gRPC</td><td>-</td><td>-</td><td>-</td><td>支持</td><td>支持</td></tr></tbody></table>

{% hint style="info" %}
`eth_sendBundle`僅針對高級特性（如0gwei、gRPC）做auth限制，如需使用高級特性請先在請求中設置Authentication，详见 [authentication](../authentication "mention")
{% endhint %}



## 請求參數

<table><thead><tr><th width="163">參數</th><th width="70">必選</th><th width="136">格式</th><th width="124">示例</th><th>描述</th></tr></thead><tbody><tr><td>txs</td><td>是</td><td>array[hex]</td><td>["0x…4b", "0x…5c"]</td><td>經過簽名的raw transaction列表</td></tr><tr><td>maxBlockNumber</td><td>否</td><td>uint64</td><td>39177941</td><td>該bundle有效的最大區塊號，默認為當前區塊號+100</td></tr><tr><td>minTimestamp</td><td>否</td><td>uint64</td><td>1710229370</td><td>期望bundle有效的最小Unix秒級時間戳</td></tr><tr><td>maxTimestamp</td><td>否</td><td>uint64</td><td>1710829390</td><td>期望bundle有效的最大Unix秒級時間戳</td></tr><tr><td>revertingTxHashes</td><td>否</td><td>array[hash]</td><td>["0x…c7", "0x…b7"]</td><td>允許丟棄的交易哈希列表</td></tr><tr><td>noMerge</td><td>否</td><td>bool</td><td>false</td><td>bundle merge可提升區塊價值，加快bundle上鏈速度，如不設置則默認為false（允許bundle merge）</td></tr></tbody></table>



## 請求示例

{% tabs %}
{% tab title="HTTPS" %}
```json
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "eth_sendBundle",
  "params": [
    {
      "txs":["0x…4b", "0x…5c"],    // 經過簽名的raw transaction列表
      "maxBlockNumber":39177941,   // 該bundle有效的最大區塊號，默認為當前區塊號+100
      "minTimestamp":1710229370,   // 期望bundle有效的最小Unix秒級時間戳
      "maxTimestamp":1710829390,   // 期望bundle有效的最大Unix秒級時間戳
      "revertingTxHashes":[
        "0x44b89abe860142d3c3bda789cf955b69ba00b71882cd968ec407a70f4719ff06", 
        "0x7d7652c685e9fda4fe2e41bad017519cffeed8ba03d59aa6401284be2ec4244c"
        ]                         // 允許丟棄的交易哈希列表
    }
  ]
}‍
```
{% endtab %}

{% tab title="gRPC" %}
```go
package main

import (
	"context"
	"crypto/ecdsa"
	"fmt"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"google.golang.org/grpc"
	"log"
	"math/big"
)

type Authentication struct {
	Token string
}

func (a *Authentication) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{
		"authorization": a.Token,
	}, nil
}

func (a *Authentication) RequireTransportSecurity() bool {
	return false // 未开启TLS鏈接则為 false，生產環境建議用true + 开启TLS
}

func main() {
	blzrelayEndPoint := "endpoint_url"

	auth := Authentication{
		Token: "your_token",
	}

	conn, err := grpc.Dial(
		blzrelayEndPoint,
		grpc.WithInsecure(), // 未开启TLS使用
		grpc.WithPerRPCCredentials(&auth),
	)
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	chainId := int64(56)
	to := common.HexToAddress("toAddress")
	pk, _ := crypto.HexToECDSA("private key")
	_, rawTx, err := GenerateAndSignTx(
		big.NewInt(0),     //value
		big.NewInt(21000), //gas limit
		big.NewInt(1e9),   //gas price
		&to, nil, 1, big.NewInt(chainId), pk)
	fmt.Printf("rawTx:%x\n", rawTx)
	if err != nil {
		log.Println("Error creating signed tx:", err)
	}
	client := sendbundle.NewBundleServiceClient(conn)
	r, err := client.SendBundle(context.Background(), &sendbundle.SendBundleArgs{
		Txs: [][]byte{
			rawTx,
		},
		//MaxBlockNumber: 1,
		//RevertingTxHashes: []string{signedTx.Hash().String()},
	})
	//r, err := client.SendTransaction(context.Background(), &sendbundle.SendTransactionArgs{Tx: rawTx})
	if err != nil {
		fmt.Println(err)
	} else {
		println("response:", r.Result)
	}
}

func GenerateAndSignTx(value, gas, gasPrice *big.Int, to *common.Address, dataBytes []byte, nonce uint64, chainID *big.Int, privateKeyECDSA *ecdsa.PrivateKey) (*types.Transaction, []byte, error) {
	tx := types.NewTx(&types.LegacyTx{
		Nonce:    nonce,
		To:       to,
		Value:    value,
		Gas:      gas.Uint64(),
		GasPrice: gasPrice,
		Data:     dataBytes,
	})
	signer := types.NewEIP155Signer(chainID)
	signedTx, err := types.SignTx(tx, signer, privateKeyECDSA)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to sign transaction: %v", err)
	}

	rawTxBytes, err := signedTx.MarshalBinary()
	if err != nil {
		return nil, nil, fmt.Errorf("failed to marshal signed transaction: %v", err)
	}

	return signedTx, rawTxBytes, nil
}
```
{% endtab %}
{% endtabs %}



### Proto

```go
syntax = "proto3";

package sendbundle;

option go_package = "internal/ethapi/sendbundle;sendbundle";

service BundleService {
  rpc SendBundle (SendBundleArgs) returns (SendBundleResponse);
  rpc SendTransaction (SendTransactionArgs) returns (SendTransactionResponse);
}

message SendBundleArgs {
  repeated bytes txs = 1;
  uint64 maxBlockNumber = 2;
  uint64 minTimestamp = 3;
  uint64 maxTimestamp = 4;
  repeated string revertingTxHashes = 5;
}

message SendTransactionArgs {
  bytes tx = 1;
}

message SendBundleResponse {
    string result = 1;
}

message SendTransactionResponse {
    string result = 1;
}
```



## 返回示例

```json
{
 "jsonrpc":"2.0",
 "id":"1",
 "result":"0xa06b……f7e8ec" //bundle哈希
}‍
```

```json
{
  "jsonrpc":"2.0",
  "id":"1",
  "error":{
    "code":-38000,
    "message":"the maxBlockNumber should not be smaller than currentBlockNum"
    }
}
```



