jito_go

package module
v0.0.0-...-e9ceb61 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 4, 2024 License: Apache-2.0 Imports: 1 Imported by: 0

README

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
  • ShredStream (under active development)
  • Geyser

📡 RPC Methods

🤡* methods which are deprecated by Jito due to malicious use

  • Searcher
    • SubscribeMempoolAccounts 🤡
    • SubscribeMempoolPrograms 🤡
    • GetNextScheduledLeader
    • GetRegions
    • GetConnectedLeaders
    • GetConnectedLeadersRegioned
    • GetTipAccounts
    • SimulateBundle
    • SendBundle
    • SendBundleWithConfirmation
    • SubscribeBundleResults
    • GetBundleStatuses (gRPC & HTTP)
  • Block Engine
    • Validator
      • SubscribePackets
      • SubscribeBundles
      • GetBlockBuilderFeeInfo
    • Relayer
      • SubscribeAccountsOfInterest
      • SubscribeProgramsOfInterest
      • StartExpiringPacketStream
  • Geyser
    • SubscribePartialAccountUpdates
    • SubscribeBlockUpdates
    • SubscribeAccountUpdates
    • SubscribeProgramUpdates
    • SubscribeTransactionUpdates
    • SubscribeSlotUpdates
  • ShredStream
  • Others (pkg/util.go)
    • SubscribeTipStream

💾 Installing

Go 1.22.0 or higher.

go get github.com/FlowGoCrazy/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

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/FlowGoCrazy/jito-go"
  "github.com/FlowGoCrazy/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]
package main

import (
  "context"
  "github.com/gagliardetto/solana-go"
  "github.com/gagliardetto/solana-go/rpc"
  "github.com/joho/godotenv"
  "github.com/FlowGoCrazy/jito-go"
  "github.com/FlowGoCrazy/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/FlowGoCrazy/jito-go"
    "github.com/FlowGoCrazy/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)
}
Subscribe Block Updates [Geyser]
package main

import (
  "context"
  "github.com/FlowGoCrazy/jito-go/clients/geyser_client"
  "log"
)

func main() {
  rpcAddr := "myGeyserRpcNodeURL"

  ctx := context.Background()

  // establish conn to geyser node...
  client, err := geyser_client.New(ctx, rpcAddr, nil)
  if err != nil {
    log.Fatal(err)
  }

  sub, _, err := client.OnBlockUpdates(ctx)
  if err != nil {
    log.Fatal(err)
  }

  // loop to read new block updates from chan
  for block := range sub {
    log.Println(block)
  }
}
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/FlowGoCrazy/jito-go"
  "github.com/FlowGoCrazy/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.

Documentation

Index

Constants

View Source
const JitoMainnet = "mainnet.rpc.jito.wtf"

Variables

View Source
var Amsterdam = JitoEndpoints["AMS"]
View Source
var Frankfurt = JitoEndpoints["FFM"]
View Source
var JitoEndpoints = map[string]JitoEndpointInfo{
	"AMS": {
		Region:            "amsterdam",
		BlockEngineURL:    "amsterdam.mainnet.block-engine.jito.wtf:443",
		RelayerURL:        "amsterdam.mainnet.relayer.jito.wtf:8100",
		ShredReceiverAddr: "74.118.140.240:1002",
		Ntp:               "ntp.amsterdam.jito.wtf",
	},
	"FFM": {
		Region:            "frankfurt",
		BlockEngineURL:    "frankfurt.mainnet.block-engine.jito.wtf:443",
		RelayerURL:        "frankfurt.mainnet.relayer.jito.wtf:8100",
		ShredReceiverAddr: "145.40.93.84:1002",
		Ntp:               "ntp.frankfurt.jito.wtf",
	},
	"NY": {
		Region:            "ny",
		BlockEngineURL:    "ny.mainnet.block-engine.jito.wtf:443",
		RelayerURL:        "ny.mainnet.relayer.jito.wtf:8100",
		ShredReceiverAddr: "141.98.216.96:1002",
		Ntp:               "ntp.dallas.jito.wtf",
	},
	"TKY": {
		Region:            "tokyo",
		BlockEngineURL:    "tokyo.mainnet.block-engine.jito.wtf:443",
		RelayerURL:        "tokyo.mainnet.relayer.jito.wtf:8100",
		ShredReceiverAddr: "202.8.9.160:1002",
		Ntp:               "ntp.tokyo.jito.wtf",
	},
	"BigD-TESTNET": {
		BlockEngineURL:    "dallas.testnet.block-engine.jito.wtf:443",
		RelayerURL:        "dallas.testnet.relayer.jito.wtf:8100",
		ShredReceiverAddr: "147.28.154.132:1002",
		Ntp:               "ntp.dallas.jito.wtf",
	},
	"NY-TESTNET": {
		BlockEngineURL:    "ny.testnet.block-engine.jito.wtf:443",
		RelayerURL:        "nyc.testnet.relayer.jito.wtf:8100",
		ShredReceiverAddr: "141.98.216.97:1002",
		Ntp:               "ntp.dallas.jito.wtf",
	},
}
View Source
var MainnetMerkleUploadAuthorityProgram = solana.MustPublicKeyFromBase58("GZctHpWXmsZC1YHACTGGcHhYxjdRqQvTpYkb9LMvxDib")
View Source
var MainnetTipAccounts = []solana.PublicKey{
	solana.MustPublicKeyFromBase58("96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5"),
	solana.MustPublicKeyFromBase58("HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe"),
	solana.MustPublicKeyFromBase58("Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY"),
	solana.MustPublicKeyFromBase58("ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49"),
	solana.MustPublicKeyFromBase58("DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh"),
	solana.MustPublicKeyFromBase58("ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt"),
	solana.MustPublicKeyFromBase58("DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL"),
	solana.MustPublicKeyFromBase58("3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT"),
}
View Source
var MainnetTipDistributionProgram = solana.MustPublicKeyFromBase58("4R3gSG8BpU4t19KYj8CfnbtRpnT8gtk4dvTHxVRwc2r7")
View Source
var MainnetTipPaymentProgram = solana.MustPublicKeyFromBase58("T1pyyaTNZsKv2WcRAB8oVnk93mLJw2XzjtVYqCsaHqt")
View Source
var NewYork = JitoEndpoints["NY"]
View Source
var TestnetDallas = JitoEndpoints["BigD-TESTNET"]
View Source
var TestnetMerkleUploadAuthorityProgram = solana.MustPublicKeyFromBase58("GZctHpWXmsZC1YHACTGGcHhYxjdRqQvTpYkb9LMvxDib")
View Source
var TestnetNewYork = JitoEndpoints["NY-TESTNET"]
View Source
var TestnetTipAccounts = []solana.PublicKey{
	solana.MustPublicKeyFromBase58("B1mrQSpdeMU9gCvkJ6VsXVVoYjRGkNA7TtjMyqxrhecH"),
	solana.MustPublicKeyFromBase58("aTtUk2DHgLhKZRDjePq6eiHRKC1XXFMBiSUfQ2JNDbN"),
	solana.MustPublicKeyFromBase58("E2eSqe33tuhAHKTrwky5uEjaVqnb2T9ns6nHHUrN8588"),
	solana.MustPublicKeyFromBase58("4xgEmT58RwTNsF5xm2RMYCnR1EVukdK8a1i2qFjnJFu3"),
	solana.MustPublicKeyFromBase58("EoW3SUQap7ZeynXQ2QJ847aerhxbPVr843uMeTfc9dxM"),
	solana.MustPublicKeyFromBase58("ARTtviJkLLt6cHGQDydfo1Wyk6M4VGZdKZ2ZhdnJL336"),
	solana.MustPublicKeyFromBase58("9n3d1K5YD2vECAbRFhFFGYNNjiXtHXJWn9F31t89vsAV"),
	solana.MustPublicKeyFromBase58("9ttgPBBhRYFuQccdR1DSnb7hydsWANoDsV3P9kaGMCEh"),
}
View Source
var TestnetTipDistributionProgram = solana.MustPublicKeyFromBase58("F2Zu7QZiTYUhPd7u9ukRVwxh7B71oA3NMJcHuCHc29P2")
View Source
var TestnetTipPaymentProgram = solana.MustPublicKeyFromBase58("DCN82qDxJAQuSqHhv2BJuAgi41SPeKZB5ioBCTMNDrCC")
View Source
var Tokyo = JitoEndpoints["TKY"]

Functions

This section is empty.

Types

type JitoEndpointInfo

type JitoEndpointInfo struct {
	Region            string
	BlockEngineURL    string
	RelayerURL        string
	ShredReceiverAddr string
	Ntp               string
}

Directories

Path Synopsis
clients

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL