This library contains tooling to interact with Jito Labs MEV software. ⚠️ Work in progress. ⚠️
We currently use gagliardetto/solana-go to interact with Solana. PRs and contributions are welcome.
If my work has been useful in building your for-profit services/infra/bots/etc, consider donating at
EcrHvqa5Vh4NhR3bitRZVrdcUGr1Z3o6bXHz7xgBU2FB
(SOL).
🤡* methods which are deprecated by Jito due to malicious use
both gRPC and JSON-RPC methods are supported
SubscribeMempoolAccounts
🤡SubscribeMempoolPrograms
🤡GetNextScheduledLeader
GetRegions
GetConnectedLeaders
GetConnectedLeadersRegioned
GetTipAccounts
SimulateBundle
SendBundle
(gRPC & RPC)SendBundleWithConfirmation
(gRPC & RPC)SubscribeBundleResults
GetBundleStatuses
(gRPC & RPC)SubscribePackets
SubscribeBundles
GetBlockBuilderFeeInfo
SubscribeAccountsOfInterest
SubscribeProgramsOfInterest
StartExpiringPacketStream
SendHeartbeat
SubscribeTipStream
RetrieveRecentBundles
Go 1.22.0 or higher.
go get github.com/weeaa/jito-go@latest
If you want to run tests:
.env
file by running task install:<os>
(darwin/linux/windows).task test
.🚨 Beware that due to duplicate types from jito proto files it will cause an error when building, this issue has been submitted to the team. 🚨
In order to get latest proto generated files, make sure you have protobuf & its plugins installed!
Using Homebrew (macOS).
brew install protobuf
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Edit perms.
chmod +x ./scripts/generate_protos.sh
Run script.
./scripts/generate_protos.sh
The following isn't mandatory anymore for Searcher access.
To access Jito MEV functionalities, you'll need a whitelisted Public Key obtained from a fresh KeyPair; submit your Public Key here.
In order to generate a new KeyPair, you can use the following function GenerateKeypair()
from the /pkg
package.
Send Bundle – gRPC
package main
import (
"context"
"github.com/davecgh/go-spew/spew"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/programs/system"
"github.com/gagliardetto/solana-go/rpc"
"github.com/joho/godotenv"
"github.com/weeaa/jito-go"
"github.com/weeaa/jito-go/clients/searcher_client"
"log"
"os"
"time"
)
func main() {
if err := godotenv.Load(); err != nil {
log.Fatal(err)
}
rpcAddr, ok := os.LookupEnv("JITO_RPC")
if !ok {
log.Fatal("JITO_RPC could not be found in .env")
}
privateKey, ok := os.LookupEnv("PRIVATE_KEY")
if !ok {
log.Fatal("PRIVATE_KEY could not be found in .env")
}
key, err := solana.PrivateKeyFromBase58(privateKey)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
client, err := searcher_client.New(
ctx,
jito_go.NewYork.BlockEngineURL,
rpc.New(rpcAddr),
rpc.New(rpc.MainNetBeta_RPC),
key,
nil,
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second)
defer cancel()
// max per bundle is 5 transactions
txns := make([]*solana.Transaction, 0, 5)
block, err := client.RpcConn.GetRecentBlockhash(context.Background(), rpc.CommitmentFinalized)
if err != nil {
log.Fatal(err)
}
// change w ur keys =)
from := solana.MustPrivateKeyFromBase58("Tq5gFBU4QG6b6aUYAwi87CUx64iy5tZT1J6nuphN4FXov3UZahMYGSbxLGhb8a9UZ1VvxWB4NzDavSzTorqKCio")
to := solana.MustPublicKeyFromBase58("BLrQPbKruZgFkNhpdGGrJcZdt1HnfrBLojLYYgnrwNrz")
tipInst, err := client.GenerateTipRandomAccountInstruction(1000000, from.PublicKey())
if err != nil {
log.Fatal(err)
}
tx, err := solana.NewTransaction(
[]solana.Instruction{
system.NewTransferInstruction(
10000000,
from.PublicKey(),
to,
).Build(),
tipInst,
},
block.Value.Blockhash,
solana.TransactionPayer(from.PublicKey()),
)
if err != nil {
log.Fatal(err)
}
if _, err = tx.Sign(
func(key solana.PublicKey) *solana.PrivateKey {
if from.PublicKey().Equals(key) {
return &from
}
return nil
},
); err != nil {
log.Fatal(err)
}
// debug print
spew.Dump(tx)
txns = append(txns, tx)
resp, err := client.BroadcastBundleWithConfirmation(ctx, txns)
if err != nil {
log.Fatal(err)
}
log.Println(resp)
}
Subscribe to MemPool Transactions [Accounts]
🚨 DISABLED 🚨package main
import (
"context"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
"github.com/joho/godotenv"
"github.com/weeaa/jito-go"
"github.com/weeaa/jito-go/clients/searcher_client"
"log"
"os"
)
func main() {
if err := godotenv.Load(); err != nil {
log.Fatal(err)
}
rpcAddr, ok := os.LookupEnv("JITO_RPC")
if !ok {
log.Fatal("JITO_RPC could not be found in .env")
}
privateKey, ok := os.LookupEnv("PRIVATE_KEY")
if !ok {
log.Fatal("PRIVATE_KEY could not be found in .env")
}
key, err := solana.PrivateKeyFromBase58(privateKey)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
client, err := searcher_client.New(
ctx,
jito_go.NewYork.BlockEngineURL,
rpc.New(rpcAddr),
rpc.New(rpc.MainNetBeta_RPC),
key,
nil,
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
regions := []string{jito_go.NewYork.Region}
accounts := []string{
"GuHvDyajPfQpHrg2oCWmArYHrZn2ynxAkSxAPFn9ht1g",
"4EKP9SRfykwQxDvrPq7jUwdkkc93Wd4JGCbBgwapeJhs",
"Hn98nGFGfZwJPjd4bk3uAX5pYHJe5VqtrtMhU54LNNhe",
"MuUEAu5tFfEMhaFGoz66jYTFBUHZrwfn3KWimXLNft2",
"CSGeQFoSuN56QZqf9WLqEEkWhRFt6QksTjMDLm68PZKA",
}
sub, _, err := client.SubscribeAccountsMempoolTransactions(ctx, accounts, regions)
if err != nil {
log.Fatal(err)
}
for tx := range sub {
log.Println(tx)
}
}
Get Regions
package main
import (
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
"github.com/weeaa/jito-go"
"github.com/weeaa/jito-go/clients/searcher_client"
"log"
"os"
)
func main() {
if err := godotenv.Load(); err != nil {
log.Fatal(err)
}
rpcAddr, ok := os.LookupEnv("JITO_RPC")
if !ok {
log.Fatal("JITO_RPC could not be found in .env")
}
privateKey, ok := os.LookupEnv("PRIVATE_KEY")
if !ok {
log.Fatal("PRIVATE_KEY could not be found in .env")
}
key, err := solana.PrivateKeyFromBase58(privateKey)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
client, err := searcher_client.New(
ctx,
jito_go.NewYork.BlockEngineURL,
rpc.New(rpcAddr),
rpc.New(rpc.MainNetBeta_RPC),
key,
nil,
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
resp, err := client.GetRegions()
if err != nil {
log.Fatal(err)
}
log.Println(resp)
}
Simulate Bundle
package main
import (
"context"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/programs/system"
"github.com/gagliardetto/solana-go/rpc"
"github.com/joho/godotenv"
"github.com/weeaa/jito-go"
"github.com/weeaa/jito-go/clients/searcher_client"
"log"
"os"
"time"
)
func main() {
if err := godotenv.Load(); err != nil {
log.Fatal(err)
}
rpcAddr, ok := os.LookupEnv("JITO_RPC")
if !ok {
log.Fatal("JITO_RPC could not be found in .env")
}
privateKey, ok := os.LookupEnv("PRIVATE_KEY")
if !ok {
log.Fatal("PRIVATE_KEY could not be found in .env")
}
key, err := solana.PrivateKeyFromBase58(privateKey)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
client, err := searcher_client.New(
ctx,
jito_go.NewYork.BlockEngineURL,
rpc.New(rpcAddr),
rpc.New(rpc.MainNetBeta_RPC),
key,
nil,
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second)
defer cancel()
var pkey string
pkey, ok = os.LookupEnv("PRIVATE_KEY_WITH_FUNDS")
if !ok {
log.Fatal("could not get PRIVATE_KEY from .env")
}
var fundedWallet solana.PrivateKey
fundedWallet, err = solana.PrivateKeyFromBase58(pkey)
if err != nil {
log.Fatal(err)
}
var blockHash *rpc.GetRecentBlockhashResult
var tx *solana.Transaction
blockHash, err = client.RpcConn.GetRecentBlockhash(ctx, rpc.CommitmentConfirmed)
if err != nil {
log.Fatal(err)
}
var tipInst solana.Instruction
tipInst, err = client.GenerateTipRandomAccountInstruction(1000000, fundedWallet.PublicKey())
if err != nil {
log.Fatal(err)
}
tx, err = solana.NewTransaction(
[]solana.Instruction{
system.NewTransferInstruction(
10000000,
fundedWallet.PublicKey(),
solana.MustPublicKeyFromBase58("A6njahNqC6qKde6YtbHdr1MZsB5KY9aKfzTY1cj8jU3v"),
).Build(),
tipInst,
},
blockHash.Value.Blockhash,
solana.TransactionPayer(fundedWallet.PublicKey()),
)
if err != nil {
log.Fatal(err)
}
_, err = tx.Sign(
func(key solana.PublicKey) *solana.PrivateKey {
if fundedWallet.PublicKey().Equals(key) {
return &fundedWallet
}
return nil
},
)
resp, err := client.SimulateBundle(
ctx,
searcher_client.SimulateBundleParams{
EncodedTransactions: []string{tx.MustToBase64()},
},
searcher_client.SimulateBundleConfig{
PreExecutionAccountsConfigs: []searcher_client.ExecutionAccounts{
{
Encoding: "base64",
Addresses: []string{"3vjULHsUbX4J2nXZJQQSHkTHoBqhedvHQPDNaAgT9dwG"},
},
},
PostExecutionAccountsConfigs: []searcher_client.ExecutionAccounts{
{
Encoding: "base64",
Addresses: []string{"3vjULHsUbX4J2nXZJQQSHkTHoBqhedvHQPDNaAgT9dwG"},
},
},
},
)
if err != nil {
log.Fatal(err)
}
log.Println(resp)
}
This library is not affiliated with Jito Labs. It is a community project and is not officially supported by Jito Labs. Use at your own risk.