Skip to content
This repository was archived by the owner on Oct 20, 2024. It is now read-only.

Commit dd93a46

Browse files
authored
Merge pull request metachris#4 from metachris/privTx
sendPrivateTransaction + cancelPrivateTransaction
2 parents 04f82fb + 983b26f commit dd93a46

File tree

7 files changed

+132
-6
lines changed

7 files changed

+132
-6
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Fork of [ethrpc](https://github.com/onrik/ethrpc) with additional [Flashbots RPC
55
* `FlashbotsCallBundle` ([`eth_callBundle`](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint/#eth_callbundle))
66
* `FlashbotsSendBundle` ([`eth_sendBundle`](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint/#eth_sendbundle))
77
* `FlashbotsGetUserStats` ([`flashbots_getUserStats`](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint/#flashbots_getuserstats))
8+
* `FlashbotsSendPrivateTransaction` (`eth_sendPrivateTransaction`)
9+
* `FlashbotsCancelPrivateTransaction` (`eth_cancelPrivateTransaction`)
810
* `FlashbotsSimulateBlock`: simulate a full block
911

1012
## Usage
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/ethereum/go-ethereum/crypto"
8+
"github.com/metachris/flashbotsrpc"
9+
)
10+
11+
var privateKey, _ = crypto.GenerateKey() // creating a new private key for testing. you probably want to use an existing key.
12+
// var privateKey, _ = crypto.HexToECDSA("YOUR_PRIVATE_KEY")
13+
14+
func main() {
15+
rpc := flashbotsrpc.New("https://relay.flashbots.net")
16+
rpc.Debug = true
17+
18+
cancelPrivTxArgs := flashbotsrpc.FlashbotsCancelPrivateTransactionRequest{
19+
TxHash: "0xYOUR_TX_HASH",
20+
}
21+
22+
cancelled, err := rpc.FlashbotsCancelPrivateTransaction(privateKey, cancelPrivTxArgs)
23+
if err != nil {
24+
if errors.Is(err, flashbotsrpc.ErrRelayErrorResponse) {
25+
// ErrRelayErrorResponse means it's a standard Flashbots relay error response, so probably a user error, rather than JSON or network error
26+
fmt.Println(err.Error())
27+
} else {
28+
fmt.Printf("error: %+v\n", err)
29+
}
30+
return
31+
}
32+
33+
// Print result
34+
fmt.Printf("was cancelled: %v\n", cancelled)
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/ethereum/go-ethereum/crypto"
8+
"github.com/metachris/flashbotsrpc"
9+
)
10+
11+
var privateKey, _ = crypto.GenerateKey() // creating a new private key for testing. you probably want to use an existing key.
12+
// var privateKey, _ = crypto.HexToECDSA("YOUR_PRIVATE_KEY")
13+
14+
func main() {
15+
rpc := flashbotsrpc.New("https://relay.flashbots.net")
16+
rpc.Debug = true
17+
18+
sendPrivTxArgs := flashbotsrpc.FlashbotsSendPrivateTransactionRequest{
19+
Tx: "0xYOUR_RAW_TX",
20+
}
21+
22+
txHash, err := rpc.FlashbotsSendPrivateTransaction(privateKey, sendPrivTxArgs)
23+
if err != nil {
24+
if errors.Is(err, flashbotsrpc.ErrRelayErrorResponse) {
25+
// ErrRelayErrorResponse means it's a standard Flashbots relay error response, so probably a user error, rather than JSON or network error
26+
fmt.Println(err.Error())
27+
} else {
28+
fmt.Printf("error: %+v\n", err)
29+
}
30+
return
31+
}
32+
33+
// Print txHash
34+
fmt.Printf("txHash: %s\n", txHash)
35+
}

examples/sendbundle/main.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package main
22

33
import (
4+
"errors"
45
"fmt"
56

67
"github.com/ethereum/go-ethereum/crypto"
78
"github.com/metachris/flashbotsrpc"
89
)
910

1011
var privateKey, _ = crypto.GenerateKey() // creating a new private key for testing. you probably want to use an existing key.
12+
// var privateKey, _ = crypto.HexToECDSA("YOUR_PRIVATE_KEY")
1113

1214
func main() {
1315
rpc := flashbotsrpc.New("https://relay.flashbots.net")
@@ -20,7 +22,12 @@ func main() {
2022

2123
result, err := rpc.FlashbotsSendBundle(privateKey, sendBundleArgs)
2224
if err != nil {
23-
fmt.Printf("%+v\n", err)
25+
if errors.Is(err, flashbotsrpc.ErrRelayErrorResponse) {
26+
// ErrRelayErrorResponse means it's a standard Flashbots relay error response, so probably a user error, rather than JSON or network error
27+
fmt.Println(err.Error())
28+
} else {
29+
fmt.Printf("error: %+v\n", err)
30+
}
2431
return
2532
}
2633

examples/userstats/main.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
package main
22

33
import (
4+
"errors"
45
"fmt"
56

67
"github.com/ethereum/go-ethereum/crypto"
78
"github.com/metachris/flashbotsrpc"
89
)
910

1011
var privateKey, _ = crypto.GenerateKey() // creating a new private key for testing. you probably want to use an existing key.
12+
// var privateKey, _ = crypto.HexToECDSA("YOUR_PRIVATE_KEY")
1113

1214
func main() {
1315
rpc := flashbotsrpc.New("https://relay.flashbots.net")
1416

1517
// Query relay for user stats
1618
result, err := rpc.FlashbotsGetUserStats(privateKey, 13281018)
1719
if err != nil {
18-
panic(err)
20+
if errors.Is(err, flashbotsrpc.ErrRelayErrorResponse) {
21+
// ErrRelayErrorResponse means it's a standard Flashbots relay error response, so probably a user error, rather than JSON or network error
22+
fmt.Println(err.Error())
23+
} else {
24+
fmt.Printf("error: %+v\n", err)
25+
}
26+
return
1927
}
2028

2129
// Print result

flashbotsrpc.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212
"os"
1313
"time"
1414

15-
"github.com/pkg/errors"
16-
1715
"github.com/ethereum/go-ethereum/accounts"
1816
"github.com/ethereum/go-ethereum/common/hexutil"
1917
"github.com/ethereum/go-ethereum/core/types"
@@ -187,7 +185,7 @@ func (rpc *FlashbotsRPC) CallWithFlashbotsSignature(method string, privKey *ecds
187185
errorResp := new(RelayErrorResponse)
188186
if err := json.Unmarshal(data, errorResp); err == nil && errorResp.Error != "" {
189187
// relay returned an error
190-
return nil, errors.New(errorResp.Error)
188+
return nil, fmt.Errorf("%w: %s", ErrRelayErrorResponse, errorResp.Error)
191189
}
192190

193191
resp := new(rpcResponse)
@@ -621,7 +619,7 @@ func (rpc *FlashbotsRPC) FlashbotsSendBundle(privKey *ecdsa.PrivateKey, param Fl
621619
return res, err
622620
}
623621

624-
// numTx is the maximum number of tx to include (used for troubleshooting). default 0 (all transactions)
622+
// Simulate a full Ethereum block. numTx is the maximum number of tx to include, used for troubleshooting (default: 0 - all transactions)
625623
func (rpc *FlashbotsRPC) FlashbotsSimulateBlock(privKey *ecdsa.PrivateKey, block *types.Block, maxTx int) (res FlashbotsCallBundleResponse, err error) {
626624
if rpc.Debug {
627625
fmt.Printf("Simulating block %s 0x%x %s \t %d tx \t timestamp: %d\n", block.Number(), block.Number(), block.Header().Hash(), len(block.Transactions()), block.Header().Time)
@@ -682,3 +680,28 @@ func (rpc *FlashbotsRPC) FlashbotsSimulateBlock(privKey *ecdsa.PrivateKey, block
682680
res, err = rpc.FlashbotsCallBundle(privKey, params)
683681
return res, err
684682
}
683+
684+
// Sends a rawTx to the Flashbots relay. It will be sent to miners as bundle for 25 blocks, after which the transaction is failed.
685+
func (rpc *FlashbotsRPC) FlashbotsSendPrivateTransaction(privKey *ecdsa.PrivateKey, param FlashbotsSendPrivateTransactionRequest) (txHash string, err error) {
686+
rawMsg, err := rpc.CallWithFlashbotsSignature("eth_sendPrivateTransaction", privKey, param)
687+
if err != nil {
688+
return "", err
689+
}
690+
err = json.Unmarshal(rawMsg, &txHash)
691+
return txHash, err
692+
}
693+
694+
// Try to cancel a private transaction at the Flashbots relay. If this call returns true this means the cancel was initiated, but it's not guaranteed
695+
// that the transaction is actually cancelled, only that it won't be sent to miners anymore. A transaction that was already sent to miners might still
696+
// be included in the next block.
697+
//
698+
// Possible errors: 'tx not found', 'tx was already cancelled', 'tx has already expired'
699+
func (rpc *FlashbotsRPC) FlashbotsCancelPrivateTransaction(privKey *ecdsa.PrivateKey, param FlashbotsCancelPrivateTransactionRequest) (cancelled bool, err error) {
700+
rawMsg, err := rpc.CallWithFlashbotsSignature("eth_cancelPrivateTransaction", privKey, param)
701+
if err != nil {
702+
// possible todo: return specific errors for the 3 possible relay-internal error cases
703+
return false, err
704+
}
705+
err = json.Unmarshal(rawMsg, &cancelled)
706+
return cancelled, err
707+
}

types.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ import (
55
"encoding/json"
66
"math/big"
77
"unsafe"
8+
9+
"github.com/pkg/errors"
810
)
911

12+
// ErrRelayErrorResponse means it's a standard Flashbots relay error response - probably a user error rather than JSON or network error
13+
var ErrRelayErrorResponse = errors.New("relay error response")
14+
1015
// Syncing - object with syncing data info
1116
type Syncing struct {
1217
IsSyncing bool
@@ -369,6 +374,7 @@ type FlashbotsCallBundleResponse struct {
369374
TotalGasUsed int64 `json:"totalGasUsed"` // 63197
370375
}
371376

377+
// sendBundle
372378
type FlashbotsSendBundleRequest struct {
373379
Txs []string `json:"txs"` // Array[String], A list of signed transactions to execute in an atomic bundle
374380
BlockNumber string `json:"blockNumber"` // String, a hex encoded block number for which this bundle is valid on
@@ -380,3 +386,13 @@ type FlashbotsSendBundleRequest struct {
380386
type FlashbotsSendBundleResponse struct {
381387
BundleHash string `json:"bundleHash"`
382388
}
389+
390+
// sendPrivateTransaction
391+
type FlashbotsSendPrivateTransactionRequest struct {
392+
Tx string `json:"tx"`
393+
}
394+
395+
// cancelPrivateTransaction
396+
type FlashbotsCancelPrivateTransactionRequest struct {
397+
TxHash string `json:"txHash"`
398+
}

0 commit comments

Comments
 (0)