GithubHelp home page GithubHelp logo

weeaa / jito-go Goto Github PK

View Code? Open in Web Editor NEW
67.0 1.0 21.0 336 KB

๐Ÿช™ Jito Go SDK [unnoficial]

Home Page: https://www.jito.wtf

License: Apache License 2.0

Go 98.68% Batchfile 0.72% Shell 0.60%
cryptocurrency jito mev

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

โœจ Features

  • Searcher
  • Block Engine
  • Relayer
  • Geyser ๐Ÿณ
  • ShredStream (under active development)
  • Others
  • GraphQL 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
    • SubscribeBundleResults
    • GetBundleStatuses (gRPC & HTTP)
  • Block Engine
    • Validator
      • SubscribePackets
      • SubscribeBundles
      • GetBlockBuilderFeeInfo
    • Relayer
      • SubscribeAccountsOfInterest
      • SubscribeProgramsOfInterest
      • StartExpiringPacketStream
  • ShredStream
  • Others (pkg/util.go)
    • SubscribeTipStream
  • GraphQL API (gql/api.go)
    • GetBundleHistory

๐Ÿ’พ 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.

๐Ÿ”‘ 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)
  }

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

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

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

  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.

๐Ÿ›Ÿ Support

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

๐Ÿ“ƒ 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

Watchers

 avatar  avatar  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 !

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

nil point

searcher_client/searcher.go:267

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

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

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.