Git Product home page Git Product logo

jito-go's Introduction

Jito Go SDK

GoDoc Go Report Card License

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.

jitolabs

โ‡๏ธ Contents

๐Ÿ›Ÿ Support

If my work has been useful in building your for-profit services/infra/bots/etc, consider donating at EcrHvqa5Vh4NhR3bitRZVrdcUGr1Z3o6bXHz7xgBU2FB (SOL).

โœจ Features

  • Searcher
  • Block Engine
  • Relayer
  • Geyser ๐Ÿณ
  • Others
  • API

๐Ÿ“ก RPC Methods

๐Ÿคก* methods which are deprecated by Jito due to malicious use

  • Searcher
    • SubscribeMempoolAccounts ๐Ÿคก
    • SubscribeMempoolPrograms ๐Ÿคก
    • GetNextScheduledLeader
    • GetRegions
    • GetConnectedLeaders
    • GetConnectedLeadersRegioned
    • GetTipAccounts
    • SimulateBundle
    • SendBundle (gRPC & HTTP)
    • SendBundleWithConfirmation (gRPC & HTTP)
    • SubscribeBundleResults
    • GetBundleStatuses (gRPC & HTTP)
  • Block Engine
    • Validator
      • SubscribePackets
      • SubscribeBundles
      • GetBlockBuilderFeeInfo
    • Relayer
      • SubscribeAccountsOfInterest
      • SubscribeProgramsOfInterest
      • StartExpiringPacketStream
  • ShredStream
  • Others (pkg/util.go)
    • SubscribeTipStream
  • API (api/api.go)
    • RetrieveRecentBundles

๐Ÿ’พ Installing

Go 1.22.0 or higher.

go get github.com/weeaa/jito-go@latest

If you want to run tests:

  1. Install Task.
  2. Initialize your .env file by running task install:<os> (darwin/linux/windows).
  3. Run tests with task test.

๐Ÿ”„ Update Proto

๐Ÿšจ 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

๐Ÿ”‘ Keypair Authentication

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.

๐Ÿ’ป Examples

Send Bundle

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)
}

๐Ÿšจ Disclaimer

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.

๐Ÿ“ƒ License

Apache-2.0 License.

jito-go's People

Contributors

0x366 avatar kidknot avatar weeaa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

jito-go's Issues

JITO mempool closed in 2024

Hi, I've seen the repo offers functionality to "[Subscribe to Mempool Transactions | Accounts], but I noticed this feature was closed due to sandwitch attacks suffered in solana.
If I am correct thi could be removed.
Thanks for your work !

nil point

searcher_client/searcher.go:267

var out *BroadcastBundleResponse
err = json.NewDecoder(resp.Body).Decode(out)

Compilation issues with protobuf files

I'm getting this error thrown when I try to compile:

# github.com/weeaa/jito-go/pb
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:116:6: SubscribePacketsRequest redeclared in this block
        ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:23:6: other declaration of SubscribePacketsRequest
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:122:35: method SubscribePacketsRequest.Reset already declared at ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:29:35
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:131:35: method SubscribePacketsRequest.String already declared at ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:38:35
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:135:33: method SubscribePacketsRequest.ProtoMessage already declared at ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:42:33
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:137:35: method SubscribePacketsRequest.ProtoReflect already declared at ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:44:35
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:150:33: method SubscribePacketsRequest.Descriptor already declared at ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:57:33
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:154:6: SubscribePacketsResponse redeclared in this block
        ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:61:6: other declaration of SubscribePacketsResponse
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:167:36: method SubscribePacketsResponse.Reset already declared at ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:70:36
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:176:36: method SubscribePacketsResponse.String already declared at ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/block_engine.pb.go:79:36
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/shredstream.pb.go:23:6: Heartbeat redeclared in this block
        ../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/shared.pb.go:71:6: other declaration of Heartbeat
../../../go/pkg/mod/github.com/weeaa/[email protected]/pb/relayer.pb.go:176:36: too many errors

I was doing some tests with the package last week and it was working fine, but I created a new project to work from and now compilation throws these errors. Didn't want to go editing generated files, as could be a bug on my end. Any thoughts?

Seems to be an issue on monitoring mempool with different accounts

Lets take an example of 2 codes
image
image

Both are tokens in SOL, one is USDC : EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v, Second is PENG : A3eME5CetyZPBoWbRUwY3tSe25S6tb18ba9ZPbWk9eFJ

for some reason the monitor doesn't work for PENG, even through transactions submitted are V0 on both

I tried to transfer money using this library and returned an error

in searcher.go

if err = c.handleBundleResult(bundleResult); err != nil {
				return nil, err
			}

			var statuses *rpc.GetSignatureStatusesResult
			statuses, err = c.RpcConn.GetSignatureStatuses(ctx, false, bundleSignatures...)
			if err != nil {
				return nil, err
			}

			for _, status := range statuses.Value {
				if status.ConfirmationStatus != rpc.ConfirmationStatusProcessed {
					return nil, errors.New("searcher service did not provide bundle status in time")
				}
			}

I tested the transfer operation using the Send Bundle method in the example, but returned an error

Panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc000000 5 code=0x0 addr=0x0 pc=0x172496e]

After inspection, it was found that the status.Value may be nil or rpc.ConfirmationStatusConfirmed an error in my call. resulting in the returned resp being nil๏ผŒHow can I obtain the tx_hash for this transaction

Bundles sending, but confirmation not recieved.

I'm sending bundles successfuly with:

func SendBundle(ctx context.Context, txs []*solana.Transaction) (*jito_pb.SendBundleResponse, error) {
	logger.Sugar.Info("Sending Bundle...")
	if len(txs) > 5 {
		return nil, fmt.Errorf("TX bundle must have len <= 5")
	}
	return client.JITO_CLIENT.BroadcastBundleWithConfirmation(ctx, txs)	
}

However the confirmation response isn't received

      res, err := executor.SendBundle(context.Background(), []*solana.Transaction{tx})
      if err != nil {
        logger.Sugar.Fatal(err)
      }

      logger.Sugar.Info(res)

My code hangs here, but i can see the successful TX on solscan / jito explorer.

Unable to intialize new no auth client

I am working on both local machine and on a windows 10 VPS.

For some reason, when tryin to initialize the client on the VPS i get the following error: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp [::1]:443: connectex: No connection could be made because the target machine actively refused it.

this is how my client is being initialized:

client, err := searcher_client.NewNoAuth(
   ctx,
   block_engine_url,
   rpc_helper.New(jito_rpc),
   rpc_helper.New(sol_rpc),
   nil,
)

Im on MacOS arm64.
A friend of mine is running on his local Windows 10 machine and is getting the same error aswell so I guess it's not only limited to VPS as I think.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.