Skip to content

Commit 43db6fb

Browse files
committed
feat: send bundle v2
1 parent 62f2aa6 commit 43db6fb

File tree

4 files changed

+153
-5
lines changed

4 files changed

+153
-5
lines changed

pkg/mev/blxr_bundle_sender.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,28 @@ func (s *BloxrouteClient) SendBundle(
9090
return s.sendBundle(ctx, p)
9191
}
9292

93+
func (s *BloxrouteClient) SendBundleV2(
94+
ctx context.Context,
95+
req SendBundleV2Request,
96+
txs ...*types.Transaction,
97+
) (SendBundleResponse, error) {
98+
p := new(BLXRSubmitBundleParams).
99+
SetTransactions(txs...)
100+
101+
if req.BlockNumber != nil {
102+
p.SetBlockNumber(*req.BlockNumber)
103+
}
104+
if req.UUID != nil {
105+
p.SetUUID(*req.UUID)
106+
}
107+
108+
if err := p.Err(); err != nil {
109+
return SendBundleResponse{}, err
110+
}
111+
112+
return s.sendBundle(ctx, p)
113+
}
114+
93115
func (s *BloxrouteClient) SendBundleHex(
94116
ctx context.Context,
95117
uuid *string,

pkg/mev/bundle_sender.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,40 @@ func (s *Client) SendBundle(
5959
return s.sendBundle(ctx, ETHSendBundleMethod, uuid, blockNumber, txs, nil)
6060
}
6161

62+
func (s *Client) SendBundleV2(
63+
ctx context.Context,
64+
req SendBundleV2Request,
65+
txs ...*types.Transaction,
66+
) (SendBundleResponse, error) {
67+
p := new(SendBundleParams).
68+
SetTransactions(txs...)
69+
70+
if req.UUID != nil {
71+
p.SetUUID(*req.UUID, s.senderType)
72+
}
73+
if req.BlockNumber != nil {
74+
p.SetBlockNumber(*req.BlockNumber)
75+
}
76+
if req.MinTimestamp != nil {
77+
p.MinTimestamp = req.MinTimestamp
78+
}
79+
if req.MaxTimestamp != nil {
80+
p.MaxTimestamp = req.MaxTimestamp
81+
}
82+
if req.RevertingTxs != nil {
83+
p.RevertingTxs = req.RevertingTxs
84+
}
85+
if s.senderType == BundleSenderTypeFlashbot {
86+
p = p.SetStateBlockNumber("latest")
87+
}
88+
89+
if err := p.Err(); err != nil {
90+
return SendBundleResponse{}, err
91+
}
92+
93+
return s.sendRawBundle(ctx, ETHSendBundleMethod, p)
94+
}
95+
6296
func (s *Client) SendBundleHex(
6397
ctx context.Context,
6498
uuid *string,
@@ -201,11 +235,6 @@ func (s *Client) sendBundle(
201235
txs []*types.Transaction,
202236
hexEncodedTxs []string,
203237
) (SendBundleResponse, error) {
204-
req := SendRequest{
205-
ID: SendBundleID,
206-
JSONRPC: JSONRPC2,
207-
Method: method,
208-
}
209238
p := new(SendBundleParams).
210239
SetBlockNumber(blockNumber).
211240
SetTransactions(txs...).
@@ -221,6 +250,16 @@ func (s *Client) sendBundle(
221250
p.SetUUID(*uuid, s.senderType)
222251
}
223252

253+
return s.sendRawBundle(ctx, method, p)
254+
}
255+
256+
func (s *Client) sendRawBundle(ctx context.Context, method string, p *SendBundleParams) (SendBundleResponse, error) {
257+
req := SendRequest{
258+
ID: SendBundleID,
259+
JSONRPC: JSONRPC2,
260+
Method: method,
261+
}
262+
224263
req.Params = append(req.Params, p)
225264

226265
reqBody, err := json.Marshal(req)

pkg/mev/bundle_sender_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,72 @@ func TestSendBundle(t *testing.T) {
8989
require.NoError(t, sender.CancelBundle(ctx, uuid))
9090
}
9191

92+
func Ptr[T any](v T) *T {
93+
return &v
94+
}
95+
96+
func TestSendBundleV2(t *testing.T) {
97+
t.Skip()
98+
99+
// Generate a new private key
100+
privateKey, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
101+
if err != nil {
102+
t.Error("Failed to generate private key:", err)
103+
return
104+
}
105+
var (
106+
endpoint = "https://bsc.blinklabs.xyz/v1/<API_KEY>"
107+
ctx = context.Background()
108+
client = http.DefaultClient
109+
bscChainID = 56
110+
)
111+
require.NoError(t, err)
112+
address := crypto.PubkeyToAddress(privateKey.PublicKey)
113+
114+
ethClient, err := ethclient.Dial("wss://bsc.kyberengineering.io")
115+
require.NoError(t, err)
116+
117+
head, err := ethClient.HeaderByNumber(ctx, nil)
118+
require.NoError(t, err)
119+
t.Log("blockNumber", head.Number)
120+
121+
nonce, err := ethClient.PendingNonceAt(ctx, address)
122+
require.NoError(t, err)
123+
124+
tip, err := convert.FloatToWei(0.3, 18)
125+
require.NoError(t, err)
126+
fee, err := convert.FloatToWei(1, 18)
127+
require.NoError(t, err)
128+
129+
tx := types.NewTx(&types.DynamicFeeTx{
130+
ChainID: big.NewInt(int64(bscChainID)),
131+
Nonce: nonce,
132+
To: &address,
133+
GasTipCap: tip,
134+
GasFeeCap: fee,
135+
Value: big.NewInt(1),
136+
})
137+
signedTx, err := types.SignTx(tx, types.NewLondonSigner(big.NewInt(int64(bscChainID))), privateKey)
138+
require.NoError(t, err)
139+
140+
t.Log("new tx", signedTx.Hash().String())
141+
142+
uuid := uuid.NewString()
143+
require.NoError(t, err)
144+
sender, err := mev.NewClient(client, endpoint, privateKey, mev.BundleSenderTypeBlink, false, false)
145+
require.NoError(t, err)
146+
147+
resp, err := sender.SendBundleV2(ctx, mev.SendBundleV2Request{
148+
MinTimestamp: Ptr(head.Time + 1),
149+
MaxTimestamp: Ptr(head.Time + 5),
150+
UUID: Ptr(uuid),
151+
})
152+
require.NoError(t, err) // sepolia: code: [-32000], message: [internal server error]
153+
t.Log("send bundle response", resp)
154+
155+
// require.NoError(t, sender.CancelBundle(ctx, uuid))
156+
}
157+
92158
func TestUnmarshal(t *testing.T) {
93159
var (
94160
data = "{\"id\":\"1\",\"result\":{\"bundleHash\":\"0xe0e0592348830d57fac820a6bec9fdbf0ac20a2b503351c63217cf8c274b70a8\"},\"jsonrpc\":\"2.0\"}\n" // nolint:lll

pkg/mev/pkg.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ type IBundleSender interface {
104104
blockNumber uint64,
105105
tx ...*types.Transaction,
106106
) (SendBundleResponse, error)
107+
SendBundleV2(
108+
ctx context.Context,
109+
req SendBundleV2Request,
110+
txs ...*types.Transaction,
111+
) (SendBundleResponse, error)
107112
SendBundleHex(
108113
ctx context.Context,
109114
uuid *string,
@@ -357,3 +362,19 @@ func CleanBundleHash(hash string) string {
357362

358363
return hash
359364
}
365+
366+
type SendBundleV2Request struct {
367+
BlockNumber *uint64 `json:"blockNumber,omitempty"`
368+
MaxBlockNumber *uint64 `json:"maxBlockNumber,omitempty"`
369+
370+
// (Optional) Number, the minimum timestamp for which this bundle is valid, in seconds since the unix epoch
371+
MinTimestamp *uint64 `json:"minTimestamp,omitempty"`
372+
// (Optional) Number, the maximum timestamp for which this bundle is valid, in seconds since the unix epoch
373+
MaxTimestamp *uint64 `json:"maxTimestamp,omitempty"`
374+
// (Optional) Array[String], A list of tx hashes that are allowed to revert
375+
RevertingTxs *[]string `json:"revertingTxHashes,omitempty"`
376+
// (Optional) String, UUID that can be used to cancel/replace this bundle
377+
ReplacementUUID *string `json:"ReplacementUuid,omitempty"`
378+
// (Optional) String, UUID that can be used to cancel/replace this bundle (For beaverbuild)
379+
UUID *string `json:"uuid,omitempty"`
380+
}

0 commit comments

Comments
 (0)