### Install Solana SDK for Go Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Install the Solana SDK for Go by navigating to your project directory and running the go get command with the desired version. ```bash $ cd my-project $ go get github.com/gagliardetto/solana-go@v1.16.0 ``` -------------------------------- ### Install Solana Go JSON-RPC Client Source: https://github.com/solana-foundation/solana-go/blob/main/rpc/jsonrpc/README.md Use 'go get' to install or update the JSON-RPC client library. ```sh go get -u github.com/ybbus/jsonrpc ``` -------------------------------- ### Basic JSON-RPC Client Usage in Go Source: https://github.com/solana-foundation/solana-go/blob/main/rpc/jsonrpc/README.md Demonstrates creating a client, calling a 'get' method, and then calling an 'update' method with modified data. Error handling is omitted for brevity. ```go type Person struct { Id int `json:"id"` Name string `json:"name"` Age int `json:"age"` } func main() { rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc") var person *Person rpcClient.CallFor(&person, "getPersonById", 4711) person.Age = 33 rpcClient.Call("updatePerson", person) } ``` -------------------------------- ### RPC-JSON Call Examples with Various Parameters Source: https://github.com/solana-foundation/solana-go/blob/main/rpc/jsonrpc/README.md Demonstrates the JSON output for different parameter types including nil, booleans, strings, numbers, floats, and complex structures passed to the `Call` method. ```go rpcClient.Call("missingParam") {"method":"missingParam"} ``` ```go rpcClient.Call("nullParam", nil) {"method":"nullParam","params":[null]} ``` ```go rpcClient.Call("boolParam", true) {"method":"boolParam","params":[true]} ``` ```go rpcClient.Call("boolParams", true, false, true) {"method":"boolParams","params":[true,false,true]} ``` ```go rpcClient.Call("stringParam", "Alex") {"method":"stringParam","params":["Alex"]} ``` ```go rpcClient.Call("stringParams", "JSON", "RPC") {"method":"stringParams","params":["JSON","RPC"]} ``` ```go rpcClient.Call("numberParam", 123) {"method":"numberParam","params":[123]} ``` ```go rpcClient.Call("numberParams", 123, 321) {"method":"numberParams","params":[123,321]} ``` ```go rpcClient.Call("floatParam", 1.23) {"method":"floatParam","params":[1.23]} ``` ```go rpcClient.Call("floatParams", 1.23, 3.21) {"method":"floatParams","params":[1.23,3.21]} ``` ```go rpcClient.Call("manyParams", "Alex", 35, true, nil, 2.34) {"method":"manyParams","params":["Alex",35,true,null,2.34]} ``` ```go rpcClient.Call("singlePointerToStruct", &person) {"method":"singlePointerToStruct","params":{"name":"Alex","age":35,"country":"Germany"}} ``` ```go rpcClient.Call("multipleStructs", &person, &drink) {"method":"multipleStructs","params":[{"name":"Alex","age":35,"country":"Germany"},{"name":"Cuba Libre","ingredients":["rum","cola"]}]} ``` ```go rpcClient.Call("singleStructInArray", []*Person{&person}) {"method":"singleStructInArray","params":[{"name":"Alex","age":35,"country":"Germany"}]} ``` ```go rpcClient.Call("namedParameters", map[string]interface{}{ "name": "Alex", "age": 35, }) {"method":"namedParameters","params":{"age":35,"name":"Alex"}} ``` ```go rpcClient.Call("anonymousStruct", struct { Name string `json:"name"` Age int `json:"age"` }{"Alex", 33}) {"method":"anonymousStructWithTags","params":{"name":"Alex","age":33}} ``` ```go rpcClient.Call("structWithNullField", struct { Name string `json:"name"` Address *string `json:"address"` }{"Alex", nil}) {"method":"structWithNullField","params":{"name":"Alex","address":null}} ``` -------------------------------- ### Decode and Use Address Lookup Tables in Go Source: https://context7.com/solana-foundation/solana-go/llms.txt This example shows how to fetch and decode an Address Lookup Table account. It also demonstrates how to construct a versioned transaction that utilizes these tables. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" lookup "github.com/gagliardetto/solana-go/programs/address-lookup-table" "github.com/gagliardetto/solana-go/rpc" ) func main() { client := rpc.New(rpc.MainNetBeta_RPC) defer client.Close() // Lookup table address tablePubkey := solana.MustPublicKeyFromBase58("LOOKUP_TABLE_ADDRESS") // Fetch lookup table account info, err := client.GetAccountInfo(context.Background(), tablePubkey) if err != nil { panic(err) } // Decode lookup table tableContent, err := lookup.DecodeAddressLookupTableState(info.GetBinary()) if err != nil { panic(err) } fmt.Printf("Lookup table is active: %v\n", tableContent.IsActive()) fmt.Printf("Number of addresses: %d\n", len(tableContent.Addresses)) for i, addr := range tableContent.Addresses { fmt.Printf(" [%d] %s\n", i, addr) } // Create transaction with address lookup tables sender, _ := solana.PrivateKeyFromBase58("YOUR_PRIVATE_KEY") recent, _ := client.GetLatestBlockhash(context.Background(), rpc.CommitmentFinalized) // Map of lookup table pubkey to addresses addressTables := map[solana.PublicKey]solana.PublicKeySlice{ tablePubkey: tableContent.Addresses, } // Build versioned transaction with lookup tables tx, err := solana.NewTransaction( []solana.Instruction{ // Your instructions here }, recent.Value.Blockhash, solana.TransactionPayer(sender.PublicKey()), solana.TransactionAddressTables(addressTables), ) if err != nil { panic(err) } fmt.Println(tx.String()) } ``` -------------------------------- ### Create a New Solana Wallet and Airdrop Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Generate a new Solana wallet using `solana.NewWallet()` and request an airdrop to its public key. This example uses the testnet cluster. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" ) func main() { // Create a new account: account := solana.NewWallet() fmt.Println("account private key:", account.PrivateKey) fmt.Println("account public key:", account.PublicKey()) // Create a new RPC client: client := rpc.New(rpc.TestNet_RPC) // Airdrop 1 SOL to the new account: out, err := client.RequestAirdrop( context.TODO(), account.PublicKey(), solana.LAMPORTS_PER_SOL*1, rpc.CommitmentFinalized, ) if err != nil { panic(err) } fmt.Println("airdrop transaction signature:", out) } ``` -------------------------------- ### Conventional Commit Examples Source: https://github.com/solana-foundation/solana-go/blob/main/CONTRIBUTING.md Provides examples of valid conventional commit messages for various types like 'feat', 'fix', 'docs', 'refactor', 'test'. ```plaintext feat: add priority fee support to SendTransaction fix: handle nil response in GetAccountInfo docs: update RPC methods table in README refactor(ws): simplify subscription reconnect logic test: add coverage for address lookup table resolution ``` -------------------------------- ### Conventional Commit Format Example Source: https://github.com/solana-foundation/solana-go/blob/main/CONTRIBUTING.md Illustrates the structure of a conventional commit message, including type, optional scope, description, and optional body/footers. ```plaintext [optional scope]: [optional body] [optional footer(s)] ``` -------------------------------- ### Resolve Address Lookup Tables in Go Source: https://github.com/solana-foundation/solana-go/blob/main/README.md This example demonstrates how to resolve address lookup tables for a versioned Solana transaction. It fetches account information for lookup table keys and updates the transaction message with resolved addresses. ```go package main import ( "context" "fmt" "time" "github.com/davecgh/go-spew/spew" "github.com/gagliardetto/solana-go" lookup "github.com/gagliardetto/solana-go/programs/address-lookup-table" "github.com/gagliardetto/solana-go/rpc" "golang.org/x/time/rate" ) func main() { cluster := rpc.MainNetBeta rpcClient := rpc.NewWithCustomRPCClient(rpc.NewWithLimiter( cluster.RPC, rate.Every(time.Second), // time frame 5, // limit of requests per time frame )) version := uint64(0) tx, err := rpcClient.GetTransaction( context.Background(), solana.MustSignatureFromBase58("24jRMP3medE9iMqVSPRbkwfe9GdPmLfeftKPuwRHZdYTZJ6UyzNMGGKo4BHrTu2zVj4CgFF3CEuzS79QXUo2CMC"), &rpc.GetTransactionOpts{ MaxSupportedTransactionVersion: &version, Encoding: solana.EncodingBase64, }, ) if err != nil { panic(err) } parsed, err := tx.Transaction.GetTransaction() if err != nil { panic(err) } processTransactionWithAddressLookups(parsed, rpcClient) } func processTransactionWithAddressLookups(txx *solana.Transaction, rpcClient *rpc.Client) { if !txx.Message.IsVersioned() { fmt.Println("tx is not versioned; only versioned transactions can contain lookups") return } tblKeys := txx.Message.GetAddressTableLookups().GetTableIDs() if len(tblKeys) == 0 { fmt.Println("no lookup tables in versioned transaction") return } numLookups := txx.Message.GetAddressTableLookups().NumLookups() if numLookups == 0 { fmt.Println("no lookups in versioned transaction") return } fmt.Println("num lookups:", numLookups) fmt.Println("num tbl keys:", len(tblKeys)) resolutions := make(map[solana.PublicKey]solana.PublicKeySlice) for _, key := range tblKeys { fmt.Println("Getting table", key) info, err := rpcClient.GetAccountInfo( context.Background(), key, ) if err != nil { panic(err) } fmt.Println("got table "+key.String()) tableContent, err := lookup.DecodeAddressLookupTableState(info.GetBinary()) if err != nil { panic(err) } fmt.Println("table content:", spew.Sdump(tableContent)) fmt.Println("isActive", tableContent.IsActive()) resolutions[key] = tableContent.Addresses } err := txx.Message.SetAddressTables(resolutions) if err != nil { panic(err) } err = txx.Message.ResolveLookups() if err != nil { panic(err) } fmt.Println(txx.String()) ``` -------------------------------- ### Breaking Change Commit Example Source: https://github.com/solana-foundation/solana-go/blob/main/CONTRIBUTING.md Demonstrates how to indicate a breaking change in a commit message using an exclamation mark after the type or a 'BREAKING CHANGE:' footer. ```plaintext feat!: remove deprecated GetRecentBlockhash method BREAKING CHANGE: GetRecentBlockhash has been removed. Use GetLatestBlockhash instead. ``` -------------------------------- ### Create and Send SOL Transfer Transaction in Go Source: https://context7.com/solana-foundation/solana-go/llms.txt Use this snippet to create a basic SOL transfer transaction. Ensure the sender's private key is funded and valid. This example uses RPC and WebSocket clients for sending and confirming the transaction. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/programs/system" "github.com/gagliardetto/solana-go/rpc" confirm "github.com/gagliardetto/solana-go/rpc/sendAndConfirmTransaction" "github.com/gagliardetto/solana-go/rpc/ws" ) func main() { // Create RPC and WebSocket clients rpcClient := rpc.New(rpc.DevNet_RPC) defer rpcClient.Close() wsClient, err := ws.Connect(context.Background(), rpc.DevNet_WS) if err != nil { panic(err) } defer wsClient.Close() // Sender's private key (fund this account first with airdrop) sender, err := solana.PrivateKeyFromBase58("YOUR_PRIVATE_KEY_BASE58") if err != nil { panic(err) } // Recipient's public key recipient := solana.MustPublicKeyFromBase58("RECIPIENT_PUBLIC_KEY") // Amount to transfer (in lamports) amount := uint64(1000000) // 0.001 SOL // Get recent blockhash recent, err := rpcClient.GetLatestBlockhash(context.Background(), rpc.CommitmentFinalized) if err != nil { panic(err) } // Create transfer instruction transferInstruction := system.NewTransferInstruction( amount, sender.PublicKey(), recipient, ).Build() // Build transaction tx, err := solana.NewTransaction( []solana.Instruction{transferInstruction}, recent.Value.Blockhash, solana.TransactionPayer(sender.PublicKey()), ) if err != nil { panic(err) } // Sign transaction _, err = tx.Sign(func(key solana.PublicKey) *solana.PrivateKey { if sender.PublicKey().Equals(key) { return &sender } return nil }) if err != nil { panic(err) } // Pretty print transaction fmt.Println(tx.String()) // Send and wait for confirmation sig, err := confirm.SendAndConfirmTransaction( context.Background(), rpcClient, wsClient, tx, ) if err != nil { panic(err) } fmt.Printf("Transaction signature: %s\n", sig) } ``` -------------------------------- ### Transfer SOL Between Wallets Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Transfers SOL from one wallet to another on the Solana DevNet. This example includes airdropping funds, constructing a transfer instruction, signing the transaction, and sending it for confirmation. ```go package main import ( "context" "fmt" "os" "time" "github.com/davecgh/go-spew/spew" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/programs/system" "github.com/gagliardetto/solana-go/rpc" confirm "github.com/gagliardetto/solana-go/rpc/sendAndConfirmTransaction" "github.com/gagliardetto/solana-go/rpc/jsonrpc" "github.com/gagliardetto/solana-go/rpc/ws" "github.com/gagliardetto/solana-go/text" ) func main() { // Create a new RPC client: rpcClient := rpc.New(rpc.DevNet_RPC) // Create a new WS client (used for confirming transactions) wsClient, err := ws.Connect(context.Background(), rpc.DevNet_WS) if err != nil { panic(err) } // Load the account that you will send funds FROM: accountFrom, err := solana.PrivateKeyFromSolanaKeygenFile("/path/to/.config/solana/id.json") if err != nil { panic(err) } fmt.Println("accountFrom private key:", accountFrom) fmt.Println("accountFrom public key:", accountFrom.PublicKey()) // The public key of the account that you will send sol TO: accountTo := solana.MustPublicKeyFromBase58("TODO") // The amount to send (in lamports); // 1 sol = 1000000000 lamports amount := uint64(3333) if true { // Airdrop 1 sol to the account so it will have something to transfer: out, err := rpcClient.RequestAirdrop( context.TODO(), accountFrom.PublicKey(), solana.LAMPORTS_PER_SOL*1, rpc.CommitmentFinalized, ) if err != nil { panic(err) } fmt.Println("airdrop transaction signature:", out) time.Sleep(time.Second * 5) } //--------------- recent, err := rpcClient.GetLatestBlockhash(context.TODO(), rpc.CommitmentFinalized) if err != nil { panic(err) } tx, err := solana.NewTransaction( []solana.Instruction{ system.NewTransferInstruction( amount, accountFrom.PublicKey(), accountTo, ).Build(), }, recent.Value.Blockhash, solana.TransactionPayer(accountFrom.PublicKey()), ) if err != nil { panic(err) } _, err = tx.Sign( func(key solana.PublicKey) *solana.PrivateKey { if accountFrom.PublicKey().Equals(key) { return &accountFrom } return nil }, ) if err != nil { panic(fmt.Errorf("unable to sign transaction: %w", err)) } spew.Dump(tx) // Pretty print the transaction: tx.EncodeTree(text.NewTreeEncoder(os.Stdout, "Transfer SOL")) // Send transaction, and wait for confirmation: sig, err := confirm.SendAndConfirmTransaction( context.TODO(), rpcClient, wsClient, tx, ) if err != nil { panic(err) } spew.Dump(sig) // Or just send the transaction WITHOUT waiting for confirmation: // sig, err := rpcClient.SendTransactionWithOpts( // context.TODO(), // tx, // false, // rpc.CommitmentFinalized, // ) // if err != nil { // panic(err) // } // spew.Dump(sig) } ``` -------------------------------- ### Decode Transaction from Base64 Source: https://context7.com/solana-foundation/solana-go/llms.txt Parse and decode a Solana transaction from its Base64 encoded string representation. This example shows how to extract signatures, instructions, and decode system program instructions. ```go package main import ( "fmt" bin "github.com/gagliardetto/binary" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/programs/system" ) func main() { // Decode from base64 base64Tx := "YOUR_BASE64_ENCODED_TRANSACTION" tx, err := solana.TransactionFromBase64(base64Tx) if err != nil { panic(err) } fmt.Printf("Signatures: %d\n", len(tx.Signatures)) fmt.Printf("Instructions: %d\n", len(tx.Message.Instructions)) // Decode each instruction for i, inst := range tx.Message.Instructions { progKey, err := tx.ResolveProgramIDIndex(inst.ProgramIDIndex) if err != nil { continue } accounts, err := inst.ResolveInstructionAccounts(&tx.Message) if err != nil { continue } // Decode if it's a system program instruction if progKey.Equals(solana.SystemProgramID) { decoded, err := system.DecodeInstruction(accounts, inst.Data) if err == nil { fmt.Printf("Instruction %d: %T\n", i, decoded.Impl) // Type assertion for Transfer if transfer, ok := decoded.Impl.(*system.Transfer); ok { fmt.Printf(" Transfer amount: %d lamports\n", *transfer.Lamports) } } } } // Pretty print the entire transaction fmt.Println(tx.String()) } ``` -------------------------------- ### Get SOL Balance for an Account Source: https://context7.com/solana-foundation/solana-go/llms.txt Retrieve the SOL balance for a given account address. The balance is returned in lamports, where 1 SOL equals 1,000,000,000 lamports. Requires the account's public key. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" ) func main() { client := rpc.New(rpc.DevNet_RPC) defer client.Close() pubKey := solana.MustPublicKeyFromBase58("7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU") // Get balance with default commitment balance, err := client.GetBalance( context.Background(), pubKey, rpc.CommitmentFinalized, ) if err != nil { panic(err) } // Balance is in lamports (1 SOL = 1,000,000,000 lamports) fmt.Printf("Balance: %d lamports\n", balance.Value) fmt.Printf("Balance: %.9f SOL\n", float64(balance.Value)/float64(solana.LAMPORTS_PER_SOL)) fmt.Printf("Context slot: %d\n", balance.Context.Slot) } ``` -------------------------------- ### Get Latest Blockhash Source: https://context7.com/solana-foundation/solana-go/llms.txt Retrieve the latest blockhash from the network, which is necessary for creating and signing transactions. This function requires a specified commitment level. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go/rpc" ) func main() { client := rpc.New(rpc.DevNet_RPC) defer client.Close() // Get latest blockhash with finalized commitment blockhash, err := client.GetLatestBlockhash( context.Background(), rpc.CommitmentFinalized, ) if err != nil { panic(err) } fmt.Printf("Blockhash: %s\n", blockhash.Value.Blockhash) fmt.Printf("Last valid block height: %d\n", blockhash.Value.LastValidBlockHeight) fmt.Printf("Context slot: %d\n", blockhash.Context.Slot) } ``` -------------------------------- ### Create Solana RPC Client Source: https://context7.com/solana-foundation/solana-go/llms.txt Demonstrates creating RPC clients for different Solana networks, including options for custom headers and rate limiting. Verifies connection by fetching the Solana version. ```go package main import ( "context" "fmt" "time" "github.com/gagliardetto/solana-go/rpc" "golang.org/x/time/rate" ) func main() { // Create a basic RPC client for devnet client := rpc.New(rpc.DevNet_RPC) // Available cluster endpoints: // rpc.MainNetBeta_RPC - "https://api.mainnet-beta.solana.com" // rpc.TestNet_RPC - "https://api.testnet.solana.com" // rpc.DevNet_RPC - "https://api.devnet.solana.com" // rpc.LocalNet_RPC - "http://127.0.0.1:8899" // Create client with custom headers (for API key authentication) clientWithHeaders := rpc.NewWithHeaders( rpc.MainNetBeta_RPC, map[string]string{ "x-api-key": "your-api-key", }, ) // Create client with rate limiting rateLimitedClient := rpc.NewWithCustomRPCClient(rpc.NewWithLimiter( rpc.MainNetBeta_RPC, rate.Every(time.Second), // time frame 5, // limit of requests per time frame )) // Get Solana version to verify connection version, err := client.GetVersion(context.Background()) if err != nil { panic(err) } fmt.Printf("Solana version: %s\n", version.SolanaCore) // Close clients when done defer client.Close() defer clientWithHeaders.Close() defer rateLimitedClient.Close() } ``` -------------------------------- ### Solana Wallet and Key Management Source: https://context7.com/solana-foundation/solana-go/llms.txt Shows how to create new wallets, load private keys from various formats (base58, JSON keygen file), derive public keys, and perform cryptographic operations like signing and verifying messages. ```go package main import ( "fmt" "github.com/gagliardetto/solana-go" ) func main() { // Create a new random wallet wallet := solana.NewWallet() fmt.Println("New wallet public key:", wallet.PublicKey()) fmt.Println("New wallet private key:", wallet.PrivateKey.String()) // Generate a new random private key privateKey, err := solana.NewRandomPrivateKey() if err != nil { panic(err) } fmt.Println("Generated private key:", privateKey.String()) fmt.Println("Derived public key:", privateKey.PublicKey().String()) // Load private key from base58 string loadedKey, err := solana.PrivateKeyFromBase58( "66cDvko73yAf8LYvFMM3r8vF5vJtkk7JKMgEKwkmBC86oHdq41C7i1a2vS3zE1yCcdLLk6VUatUb32ZzVjSBXtRs", ) if err != nil { panic(err) } fmt.Println("Loaded public key:", loadedKey.PublicKey().String()) // Load from Solana CLI keygen file (JSON format) keyFromFile, err := solana.PrivateKeyFromSolanaKeygenFile("/path/to/keypair.json") if err != nil { panic(err) } fmt.Println("File public key:", keyFromFile.PublicKey().String()) // Parse public key from base58 string pubKey, err := solana.PublicKeyFromBase58("F8UvVsKnzWyp2nF8aDcqvQ2GVcRpqT91WDsAtvBKCMt9") if err != nil { panic(err) } fmt.Println("Parsed public key:", pubKey.String()) // Use MustPublicKeyFromBase58 for known-good keys (panics on error) knownPubKey := solana.MustPublicKeyFromBase58("F8UvVsKnzWyp2nF8aDcqvQ2GVcRpqT91WDsAtvBKCMt9") fmt.Println("Known public key:", knownPubKey.String()) // Sign a message message := []byte("Hello, Solana!") signature, err := privateKey.Sign(message) if err != nil { panic(err) } fmt.Println("Signature:", signature.String()) // Verify signature isValid := privateKey.PublicKey().Verify(message, signature) fmt.Println("Signature valid:", isValid) } ``` -------------------------------- ### Configure Client with a Custom HTTP Client (e.g., for Proxy) Source: https://github.com/solana-foundation/solana-go/blob/main/rpc/jsonrpc/README.md Provide a custom http.Client instance to NewClientWithOpts to control network behavior, such as routing requests through a proxy server. This offers flexibility for specific network requirements. ```go func main() { proxyURL, _ := url.Parse("http://proxy:8080") transport := &http.Transport{Proxy: http.ProxyURL(proxyURL)} httpClient := &http.Client{ Transport: transport, } rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{ HTTPClient: httpClient, }) // requests now use proxy } ``` -------------------------------- ### Configure Rate Limiting for RPC Client Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Use `rpc.NewWithLimiter` to create an RPC client that respects rate limits. Configure the time frame and the maximum number of requests allowed within that frame. ```go package main import ( "context" "golang.org/x/time/rate" "github.com/davecgh/go-spew/spew" "github.com/gagliardetto/solana-go/rpc" ) func main() { cluster := rpc.MainNetBeta client := rpc.NewWithCustomRPCClient(rpc.NewWithLimiter( cluster.RPC, rate.Every(time.Second), // time frame 5, // limit of requests per time frame )) out, err := client.GetVersion( context.TODO(), ) if err != nil { panic(err) } spew.Dump(out) } ``` -------------------------------- ### Configure Client with OAuth Credentials Source: https://github.com/solana-foundation/solana-go/blob/main/rpc/jsonrpc/README.md Integrate OAuth authentication by providing a configured oauth.Config to the HTTPClient option in NewClientWithOpts. This enables the client to automatically retrieve and use OAuth tokens for requests. ```go func main() { credentials := clientcredentials.Config{ ClientID: "myID", ClientSecret: "mySecret", TokenURL: "http://mytokenurl", } rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{ HTTPClient: credentials.Client(context.Background()), }) // requests now retrieve and use an oauth token } ``` -------------------------------- ### Set Compute Budget Instructions in Go Source: https://context7.com/solana-foundation/solana-go/llms.txt Use this snippet to set compute unit price and limit for priority fees in a Solana transaction. Ensure the compute budget instructions are added before your main transaction instructions. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/programs/compute-budget" "github.com/gagliardetto/solana-go/programs/system" "github.com/gagliardetto/solana-go/rpc" ) func main() { client := rpc.New(rpc.DevNet_RPC) defer client.Close() sender, _ := solana.PrivateKeyFromBase58("YOUR_PRIVATE_KEY") recipient := solana.MustPublicKeyFromBase58("RECIPIENT") recent, _ := client.GetLatestBlockhash(context.Background(), rpc.CommitmentFinalized) // Set compute unit price (priority fee in micro-lamports per CU) setComputeUnitPrice := compute_budget.NewSetComputeUnitPriceInstruction(1000).Build() // Set compute unit limit setComputeUnitLimit := compute_budget.NewSetComputeUnitLimitInstruction(200000).Build() // Your main instruction transfer := system.NewTransferInstruction( 1000000, sender.PublicKey(), recipient, ).Build() // Build transaction with compute budget instructions first tx, err := solana.NewTransaction( []solana.Instruction{ setComputeUnitPrice, setComputeUnitLimit, transfer, }, recent.Value.Blockhash, solana.TransactionPayer(sender.PublicKey()), ) if err != nil { panic(err) } tx.Sign(func(key solana.PublicKey) *solana.PrivateKey { if sender.PublicKey().Equals(key) { return &sender } return nil }) fmt.Println(tx.String()) } ``` -------------------------------- ### Load Private Key from Solana Keygen File Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Loads a private key from a JSON file generated by `solana-keygen`. Ensure the file path is correct. ```go { // Load private key from a json file generated with // $ solana-keygen new --outfile=standard.solana-keygen.json privateKey, err := solana.PrivateKeyFromSolanaKeygenFile("/path/to/standard.solana-keygen.json") if err != nil { panic(err) } fmt.Println("private key:", privateKey.String()) // To get the public key, you need to call the `PublicKey()` method: publicKey := privateKey.PublicKey() // To get the base58 string of a public key, you can call the `String()` method: fmt.Println("public key:", publicKey.String()) } ``` -------------------------------- ### Run All Tests in solana-go Source: https://github.com/solana-foundation/solana-go/blob/main/CONTRIBUTING.md Execute all tests within the solana-go project. Use the -count=1 flag to ensure tests are run fresh without caching. ```bash go test ./... -count=1 ``` -------------------------------- ### Generate Basic RPC-JSON Request Source: https://github.com/solana-foundation/solana-go/blob/main/rpc/jsonrpc/README.md Use `jsonrpc.NewClient` to create a client and `Call` to send a simple method request without parameters. Always check for errors in production. ```go func main() { rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc") rpcClient.Call("getDate") // generates body: {"method":"getDate","id":1,"jsonrpc":"2.0"} } ``` -------------------------------- ### Simulate Transaction Before Sending Source: https://context7.com/solana-foundation/solana-go/llms.txt Use SimulateTransactionWithOpts to simulate a transaction and check for errors before broadcasting it. This is useful for validating transaction logic and estimating resource consumption. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/programs/system" "github.com/gagliardetto/solana-go/rpc" ) func main() { client := rpc.New(rpc.DevNet_RPC) defer client.Close() sender, _ := solana.PrivateKeyFromBase58("YOUR_PRIVATE_KEY") recipient := solana.MustPublicKeyFromBase58("RECIPIENT") recent, _ := client.GetLatestBlockhash(context.Background(), rpc.CommitmentFinalized) tx, _ := solana.NewTransaction( []solana.Instruction{ system.NewTransferInstruction( 1000000, sender.PublicKey(), recipient, ).Build(), }, recent.Value.Blockhash, solana.TransactionPayer(sender.PublicKey()), ) tx.Sign(func(key solana.PublicKey) *solana.PrivateKey { if sender.PublicKey().Equals(key) { return &sender } return nil }) // Simulate transaction result, err := client.SimulateTransactionWithOpts( context.Background(), tx, &rpc.SimulateTransactionOpts{ Commitment: rpc.CommitmentProcessed, ReplaceRecentBlockhash: true, InnerInstructions: true, }, ) if err != nil { panic(err) } if result.Value.Err != nil { fmt.Printf("Simulation failed: %v\n", result.Value.Err) } else { fmt.Println("Simulation succeeded!") fmt.Printf("Units consumed: %d\n", *result.Value.UnitsConsumed) } // Print logs for _, log := range result.Value.Logs { fmt.Println(log) } } ``` -------------------------------- ### Configure Client with Custom Headers for Basic Authentication Source: https://github.com/solana-foundation/solana-go/blob/main/rpc/jsonrpc/README.md Set custom headers, such as the Authorization header for Basic Authentication, when creating the RPC client using NewClientWithOpts. This allows for secure access to protected RPC services. ```go func main() { rpcClient := jsonrpc.NewClientWithOpts("http://my-rpc-service:8080/rpc", &jsonrpc.RPCClientOpts{ CustomHeaders: map[string]string{ "Authorization": "Basic " + base64.StdEncoding.EncodeToString([]byte("myUser"+":"+"mySecret")), }, }) response, _ := rpcClient.Call("addNumbers", 1, 2) // send with Authorization-Header } ``` -------------------------------- ### Create Custom HTTP Client for RPC Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Configure a custom `http.Client` with specific transport settings like timeouts and connection pooling. This client can then be used to initialize the Solana RPC client. ```go import ( "net" "net/http" "time" "github.com/gagliardetto/solana-go/rpc" "github.com/gagliardetto/solana-go/rpc/jsonrpc" ) func NewHTTPTransport( timeout time.Duration, maxIdleConnsPerHost int, keepAlive time.Duration, ) *http.Transport { return &http.Transport{ IdleConnTimeout: timeout, MaxIdleConnsPerHost: maxIdleConnsPerHost, Proxy: http.ProxyFromEnvironment, Dial: (&net.Dialer{ Timeout: timeout, KeepAlive: keepAlive, }).Dial, } } // NewHTTP returns a new Client from the provided config. func NewHTTP( timeout time.Duration, maxIdleConnsPerHost int, keepAlive time.Duration, ) *http.Client { tr := NewHTTPTransport( timeout, maxIdleConnsPerHost, keepAlive, ) return &http.Client{ Timeout: timeout, Transport: tr, } } // NewRPC creates a new Solana JSON RPC client. func NewRPC(rpcEndpoint string) *rpc.Client { var ( defaultMaxIdleConnsPerHost = 10 defaultTimeout = 25 * time.Second defaultKeepAlive = 180 * time.Second ) opts := &jsonrpc.RPCClientOpts{ HTTPClient: NewHTTP( defaultTimeout, defaultMaxIdleConnsPerHost, defaultKeepAlive, ), } rpcClient := jsonrpc.NewClientWithOpts(rpcEndpoint, opts) return rpc.NewWithCustomRPCClient(rpcClient) } ``` -------------------------------- ### Fetch Detailed Account Information Source: https://context7.com/solana-foundation/solana-go/llms.txt Fetch detailed information about an account, including its lamport balance, owner, and executable status. Supports options for encoding, commitment level, and data slicing. Requires the account's public key. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" ) func main() { client := rpc.New(rpc.DevNet_RPC) defer client.Close() pubKey := solana.MustPublicKeyFromBase58("7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU") // Basic account info request accountInfo, err := client.GetAccountInfo(context.Background(), pubKey) if err != nil { panic(err) } fmt.Printf("Lamports: %d\n", accountInfo.Value.Lamports) fmt.Printf("Owner: %s\n", accountInfo.Value.Owner) fmt.Printf("Executable: %v\n", accountInfo.Value.Executable) fmt.Printf("Data length: %d bytes\n", len(accountInfo.GetBinary())) // With options: encoding, commitment, data slice accountInfoWithOpts, err := client.GetAccountInfoWithOpts( context.Background(), pubKey, &rpc.GetAccountInfoOpts{ Encoding: solana.EncodingBase64, Commitment: rpc.CommitmentFinalized, // Optional: limit returned data DataSlice: &rpc.DataSlice{ Offset: new(uint64), // start at byte 0 Length: func() *uint64 { v := uint64(100); return &v }(), // first 100 bytes }, }, ) if err != nil { panic(err) } fmt.Printf("Context slot: %d\n", accountInfoWithOpts.Context.Slot) } ``` -------------------------------- ### Find Program Derived Addresses (PDAs) Source: https://context7.com/solana-foundation/solana-go/llms.txt This snippet demonstrates how to find and create Program Derived Addresses (PDAs) using seeds and a program ID. It also shows how to find ATA and Token Metadata addresses. ```go package main import ( "fmt" "github.com/gagliardetto/solana-go" ) func main() { programID := solana.MustPublicKeyFromBase58("YOUR_PROGRAM_ID") // Find PDA with seeds seeds := [][]byte{ []byte("my-seed"), []byte("another-seed"), } pda, bumpSeed, err := solana.FindProgramAddress(seeds, programID) if err != nil { panic(err) } fmt.Printf("PDA: %s\n", pda) fmt.Printf("Bump seed: %d\n", bumpSeed) // Create program address with known bump address, err := solana.CreateProgramAddress( append(seeds, []byte{bumpSeed}), programID, ) if err != nil { panic(err) } fmt.Printf("Created address: %s\n", address) // Find associated token address wallet := solana.MustPublicKeyFromBase58("WALLET_ADDRESS") mint := solana.MustPublicKeyFromBase58("TOKEN_MINT") ataAddress, bump, err := solana.FindAssociatedTokenAddress(wallet, mint) if err != nil { panic(err) } fmt.Printf("ATA: %s, bump: %d\n", ataAddress, bump) // Find token metadata address metadataAddress, metadataBump, err := solana.FindTokenMetadataAddress(mint) if err != nil { panic(err) } fmt.Printf("Metadata PDA: %s, bump: %d\n", metadataAddress, metadataBump) } ``` -------------------------------- ### Add Custom Headers to RPC Client Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Initialize an RPC client with custom HTTP headers using `rpc.NewWithHeaders`. This is useful for authentication or passing specific metadata to the RPC provider. ```go package main import ( "context" "golang.org/x/time/rate" "github.com/davecgh/go-spew/spew" "github.com/gagliardetto/solana-go/rpc" ) func main() { cluster := rpc.MainNetBeta client := rpc.NewWithHeaders( cluster.RPC, map[string]string{ "x-api-key": "...", }, ) out, err := client.GetVersion( context.TODO(), ) if err != nil { panic(err) } spew.Dump(out) } ``` -------------------------------- ### Fetch Accounts Owned by a Program Source: https://context7.com/solana-foundation/solana-go/llms.txt Use GetProgramAccountsWithOpts to fetch accounts owned by a specific program ID. Supports filtering by data size and memory comparison for specific data patterns. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" ) func main() { client := rpc.New(rpc.MainNetBeta_RPC) defer client.Close() // Token Program ID tokenProgramID := solana.TokenProgramID // Get all token accounts with filters accounts, err := client.GetProgramAccountsWithOpts( context.Background(), tokenProgramID, &rpc.GetProgramAccountsOpts{ Encoding: solana.EncodingBase64, Commitment: rpc.CommitmentFinalized, Filters: []rpc.RPCFilter{ // Filter by account data size (Token accounts are 165 bytes) {DataSize: 165}, // Filter by mint address at offset 0 { Memcmp: &rpc.RPCFilterMemcmp{ Offset: 0, Bytes: solana.MustPublicKeyFromBase58("TOKEN_MINT_ADDRESS").Bytes(), }, }, }, }, ) if err != nil { panic(err) } fmt.Printf("Found %d accounts\n", len(accounts)) for _, acc := range accounts { fmt.Printf("Account: %s, Lamports: %d\n", acc.Pubkey, acc.Account.Lamports) } } ``` -------------------------------- ### Make Basic RPC-JSON Call Source: https://github.com/solana-foundation/solana-go/blob/main/rpc/jsonrpc/README.md Initiates a JSON-RPC call to a specified endpoint and handles potential network or HTTP errors. ```go func main() { rpcClient := jsonrpc.NewClient("http://my-rpc-service:8080/rpc") response, err := rpcClient.Call("addNumbers", 1, 2) if err != nil { // error handling goes here e.g. network / http error } } ``` -------------------------------- ### Generate New Random Private Key Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Generates a new random private key. `solana.NewWallet()` can be used as a convenient wrapper for generating a new private key. ```go { // Generate a new key pair: { privateKey, err := solana.NewRandomPrivateKey() if err != nil { panic(err) } _ = privateKey } { { // Generate a new private key (a Wallet struct is just a wrapper around a private key) account := solana.NewWallet() _ = account } } } ``` -------------------------------- ### Pretty-Print Solana Transactions and Instructions Source: https://github.com/solana-foundation/solana-go/blob/main/README.md Pretty-print a Solana transaction using its String() method. This is useful for debugging and visualizing transaction details. Ensure you have a valid transaction object and necessary imports. ```go tx, err := solana.NewTransaction( []solana.Instruction{ system.NewTransferInstruction( amount, accountFrom.PublicKey(), accountTo, ).Build(), }, recent.Value.Blockhash, solana.TransactionPayer(accountFrom.PublicKey()), ) ... // Pretty print the transaction: fmt.Println(tx.String()) // OR you can choose a destination and a title: // tx.EncodeTree(text.NewTreeEncoder(os.Stdout, "Transfer SOL")) ``` -------------------------------- ### Subscribe to Real-time Account Changes via WebSocket Source: https://context7.com/solana-foundation/solana-go/llms.txt Connect to a Solana WebSocket endpoint and subscribe to real-time changes for a specific account. Ensure you have the correct account public key and a stable WebSocket connection. ```go package main import ( "context" "fmt" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" "github.com/gagliardetto/solana-go/rpc/ws" ) func main() { // Connect to WebSocket wsClient, err := ws.Connect(context.Background(), rpc.DevNet_WS) if err != nil { panic(err) } defer wsClient.Close() accountToWatch := solana.MustPublicKeyFromBase58("ACCOUNT_TO_WATCH") // Subscribe to account changes sub, err := wsClient.AccountSubscribe( accountToWatch, rpc.CommitmentFinalized, ) if err != nil { panic(err) } defer sub.Unsubscribe() fmt.Println("Subscribed to account changes...") // Listen for updates for { result, err := sub.Recv(context.Background()) if err != nil { fmt.Printf("Error receiving: %v\n", err) break } fmt.Printf("Account updated at slot %d\n", result.Context.Slot) fmt.Printf("Lamports: %d\n", result.Value.Lamports) fmt.Printf("Owner: %s\n", result.Value.Owner) fmt.Printf("Data length: %d\n", len(result.Value.Data.GetBinary())) } } ```