> ## Documentation Index
> Fetch the complete documentation index at: https://www.solanagun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# RPC

> Send Solana transactions through Solana Gun using your preferred Solana SDK.

export const EndpointsTable = ({protocol} = {}) => {
  const [copied, setCopied] = useState(null);
  const regions = [{
    name: "Frankfurt, Germany",
    code: "FRA1",
    host: "fra1.solanagun.com"
  }, {
    name: "Frankfurt, Germany",
    code: "FRA2",
    host: "fra2.solanagun.com"
  }, {
    name: "Frankfurt, Germany",
    code: "FRA3",
    host: "fra3.solanagun.com"
  }, {
    name: "Amsterdam, Netherlands",
    code: "AMS1",
    host: "ams1.solanagun.com"
  }, {
    name: "London, UK",
    code: "LON1",
    host: "lon1.solanagun.com"
  }, {
    name: "New York, USA",
    code: "NYC1",
    host: "nyc1.solanagun.com"
  }, {
    name: "Ashburn, USA",
    code: "ASH1",
    host: "ash1.solanagun.com"
  }, {
    name: "Tokyo, Japan",
    code: "TYO1",
    host: "tyo1.solanagun.com"
  }];
  const allProtocols = [{
    name: "RPC",
    url: host => `https://${host}:8875`
  }, {
    name: "WebSocket",
    url: host => `wss://${host}:8875`
  }, {
    name: "QUIC",
    url: host => `${host}:7000`
  }];
  const protocols = protocol ? allProtocols.filter(p => p.name === protocol) : allProtocols;
  const showProtocol = protocols.length > 1;
  const copy = value => {
    navigator.clipboard.writeText(value).then(() => {
      setCopied(value);
      setTimeout(() => setCopied(current => current === value ? null : current), 1500);
    });
  };
  const cell = "px-4 py-2 border-b border-white/10 align-middle";
  return <div className="not-prose my-6 overflow-x-auto rounded-xl border border-white/10" style={{
    backgroundColor: "#131313"
  }}>
      <table className="w-full text-sm text-left" style={{
    borderCollapse: "collapse"
  }}>
        <thead>
          <tr className="text-white/70">
            <th className={`${cell} font-semibold`}>Location</th>
            {showProtocol && <th className={`${cell} font-semibold`}>Protocol</th>}
            <th className={`${cell} font-semibold`}>Endpoint</th>
          </tr>
        </thead>
        <tbody className="text-white/90">
          {regions.map(region => protocols.map((proto, i) => {
    const value = proto.url(region.host);
    const isCopied = copied === value;
    return <tr key={value}>
                  {i === 0 && <td rowSpan={protocols.length} className={cell} style={{
      whiteSpace: "nowrap"
    }}>
                      <div className="font-medium">{region.name}</div>
                      <div className="text-xs text-white/50">{region.code}</div>
                    </td>}
                  {showProtocol && <td className={cell} style={{
      whiteSpace: "nowrap"
    }}>{proto.name}</td>}
                  <td className={cell}>
                    <div style={{
      display: "flex",
      alignItems: "center",
      gap: "12px"
    }}>
                      <span className="font-mono text-sm text-white" style={{
      whiteSpace: "nowrap"
    }}>{value}</span>
                      <span style={{
      position: "relative",
      display: "inline-flex",
      flexShrink: 0
    }}>
                        <button type="button" onClick={() => copy(value)} title="Copy" aria-label={`Copy ${value}`} className="pn-copy-button">
                          {isCopied ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                              <path d="M20 6 9 17l-5-5" />
                            </svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                              <rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
                              <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
                            </svg>}
                        </button>
                        {isCopied && <span role="status" className="rounded-md bg-white px-2 py-1 text-xs font-medium text-black shadow" style={{
      position: "absolute",
      bottom: "calc(100% + 6px)",
      left: "50%",
      transform: "translateX(-50%)",
      whiteSpace: "nowrap",
      pointerEvents: "none"
    }}>
                            Copied!
                          </span>}
                      </span>
                    </div>
                  </td>
                </tr>;
  }))}
        </tbody>
      </table>
    </div>;
};

## Before you begin

* Use your Solana Gun endpoint ([see below](#endpoints)). Replace the placeholders with your connection details.
* Have a funded Solana wallet and its local keypair JSON file. The examples send 0.0021 SOL (2,100,000 lamports) to an existing wallet, plus the network fee.
* Use a regular Solana RPC to fetch a recent blockhash. The examples use `https://solana-rpc.publicnode.com`.

## Endpoints

Choose a host close to your application and copy the endpoint.

<EndpointsTable protocol="RPC" />

## Send a transaction

Choose your language below. Each example signs locally and submits directly through the SDK.

<Info>
  `skipPreflight` must be enabled because Solana Gun does not simulate individual transactions. The examples set it for you.
</Info>

<Tabs>
  <Tab title="JavaScript (Node.js)">
    <Steps>
      <Step title="Install the SDK">
        Use Node.js 22.12 or later with [@solana/web3.js](https://solana-foundation.github.io/solana-web3.js/):

        ```bash theme={"system"}
        npm install @solana/web3.js@1
        ```
      </Step>

      <Step title="Write the code">
        Save the code as `send.mjs` and replace the endpoint, keypair path, and recipient address:

        ```javascript send.mjs theme={"system"}
        import {
          Connection, Keypair, PublicKey, SystemProgram,
          TransactionMessage, VersionedTransaction,
        } from "@solana/web3.js";
        import { readFileSync } from "node:fs";

        const KEYPAIR_PATH = "/path/to/keypair.json";
        const RPC_URL = "https://solana-rpc.publicnode.com";
        const GUN_URL = "https://fra1.solanagun.com:8875/<TOKEN>";
        const RECIPIENT_ADDRESS = "<RECIPIENT_ADDRESS>";
        const AMOUNT_LAMPORTS = 1_000_000;

        const payer = Keypair.fromSecretKey(
          Uint8Array.from(JSON.parse(readFileSync(KEYPAIR_PATH, "utf8"))),
        );
        const recipient = new PublicKey(RECIPIENT_ADDRESS);

        const rpc = new Connection(RPC_URL, "confirmed");
        const { blockhash } = await rpc.getLatestBlockhash();

        const message = new TransactionMessage({
          payerKey: payer.publicKey,
          recentBlockhash: blockhash,
          instructions: [
            SystemProgram.transfer({
              fromPubkey: payer.publicKey,
              toPubkey: recipient,
              lamports: AMOUNT_LAMPORTS,
            }),
          ],
        }).compileToV0Message();

        const transaction = new VersionedTransaction(message);
        transaction.sign([payer]);

        const gun = new Connection(GUN_URL, {
          fetch: (url, options) => fetch(url, {
            ...options, signal: AbortSignal.timeout(30_000),
          }),
        });

        try {
          const signature = await gun.sendRawTransaction(transaction.serialize(), {
            skipPreflight: true,
          });
          console.log("Submitted. Transaction signature:", signature);
        } catch (error) {
          console.error("Submission failed:", error.message);
          process.exitCode = 1;
        }
        ```
      </Step>

      <Step title="Run">
        ```bash theme={"system"}
        node send.mjs
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Python">
    <Steps>
      <Step title="Install the SDK">
        Install the SDK version used by this example:

        ```bash theme={"system"}
        python3 -m pip install solana==0.36.9
        ```
      </Step>

      <Step title="Write the code">
        Save the code as `send.py` and replace the endpoint, keypair path, and recipient address:

        ```python send.py theme={"system"}
        import asyncio
        from pathlib import Path

        from solana.rpc.async_api import AsyncClient
        from solana.rpc.types import TxOpts
        from solders.keypair import Keypair
        from solders.message import MessageV0
        from solders.pubkey import Pubkey
        from solders.system_program import TransferParams, transfer
        from solders.transaction import VersionedTransaction

        KEYPAIR_PATH = "/path/to/keypair.json"
        RPC_URL = "https://solana-rpc.publicnode.com"
        GUN_URL = "https://fra1.solanagun.com:8875/<TOKEN>"
        RECIPIENT_ADDRESS = "<RECIPIENT_ADDRESS>"
        AMOUNT_LAMPORTS = 1_000_000

        async def main():
            payer = Keypair.from_json(Path(KEYPAIR_PATH).read_text())
            recipient = Pubkey.from_string(RECIPIENT_ADDRESS)

            async with AsyncClient(RPC_URL, timeout=30) as rpc:
                blockhash = (await rpc.get_latest_blockhash(commitment="confirmed")).value.blockhash

            instruction = transfer(TransferParams(
                from_pubkey=payer.pubkey(),
                to_pubkey=recipient,
                lamports=AMOUNT_LAMPORTS,
            ))
            message = MessageV0.try_compile(payer.pubkey(), [instruction], [], blockhash)
            transaction = VersionedTransaction(message, [payer])

            async with AsyncClient(GUN_URL, timeout=30) as gun:
                response = await gun.send_raw_transaction(
                    bytes(transaction), opts=TxOpts(skip_preflight=True),
                )
                print("Submitted. Transaction signature:", response.value)

        asyncio.run(main())
        ```
      </Step>

      <Step title="Run">
        ```bash theme={"system"}
        python3 send.py
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Go">
    <Steps>
      <Step title="Install the SDK">
        Create a directory for the example and install [solana-go](https://github.com/gagliardetto/solana-go):

        ```bash theme={"system"}
        mkdir solana-gun-go
        cd solana-gun-go
        go mod init solana-gun-example
        go get github.com/gagliardetto/solana-go@v1.14.0
        ```
      </Step>

      <Step title="Write the code">
        Save the code as `main.go` and replace the endpoint, keypair path, and recipient address:

        ```go main.go theme={"system"}
        package main

        import (
        	"context"
        	"fmt"
        	"time"

        	"github.com/gagliardetto/solana-go"
        	"github.com/gagliardetto/solana-go/programs/system"
        	"github.com/gagliardetto/solana-go/rpc"
        )

        const (
        	KEYPAIR_PATH             = "/path/to/keypair.json"
        	RPC_URL                  = "https://solana-rpc.publicnode.com"
        	GUN_URL                  = "https://fra1.solanagun.com:8875/<TOKEN>"
        	RECIPIENT_ADDRESS        = "<RECIPIENT_ADDRESS>"
        	AMOUNT_LAMPORTS   uint64 = 1_000_000
        )

        func main() {
        	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
        	defer cancel()

        	payer, err := solana.PrivateKeyFromSolanaKeygenFile(KEYPAIR_PATH)
        	if err != nil {
        		panic(err)
        	}
        	recipient := solana.MustPublicKeyFromBase58(RECIPIENT_ADDRESS)

        	source := rpc.New(RPC_URL)
        	latest, err := source.GetLatestBlockhash(ctx, rpc.CommitmentConfirmed)
        	if err != nil {
        		panic(err)
        	}

        	transaction, err := solana.NewTransaction(
        		[]solana.Instruction{
        			system.NewTransferInstruction(AMOUNT_LAMPORTS, payer.PublicKey(), recipient).Build(),
        		},
        		latest.Value.Blockhash,
        		solana.TransactionPayer(payer.PublicKey()),
        	)
        	if err != nil {
        		panic(err)
        	}

        	_, err = transaction.Sign(func(key solana.PublicKey) *solana.PrivateKey {
        		if key == payer.PublicKey() {
        			return &payer
        		}
        		return nil
        	})
        	if err != nil {
        		panic(err)
        	}

        	gun := rpc.New(GUN_URL)
        	signature, err := gun.SendTransactionWithOpts(ctx, transaction, rpc.TransactionOpts{SkipPreflight: true})
        	if err != nil {
        		panic(err)
        	}

        	fmt.Println("Submitted. Transaction signature:", signature)
        }
        ```
      </Step>

      <Step title="Run">
        ```bash theme={"system"}
        go mod tidy
        go run .
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Rust">
    <Steps>
      <Step title="Create a Rust project">
        ```bash theme={"system"}
        cargo new solana-gun-rpc-example
        cd solana-gun-rpc-example
        ```
      </Step>

      <Step title="Add dependencies">
        Replace the `[dependencies]` section in `Cargo.toml` with:

        ```toml Cargo.toml theme={"system"}
        [dependencies]
        anyhow = "1"
        solana-client = "=2.3.13"
        solana-sdk = "=2.3.1"
        tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
        ```
      </Step>

      <Step title="Write the code">
        Save the code as `src/main.rs` and replace the endpoint, keypair path, and recipient address:

        ```rust src/main.rs theme={"system"}
        use solana_client::{
            nonblocking::rpc_client::RpcClient,
            rpc_config::RpcSendTransactionConfig,
        };
        use solana_sdk::{
            commitment_config::CommitmentConfig,
            pubkey::Pubkey,
            signature::{read_keypair_file, Signer},
            system_instruction,
            transaction::{Transaction, VersionedTransaction},
        };
        use std::time::Duration;

        const KEYPAIR_PATH: &str = "/path/to/keypair.json";
        const RPC_URL: &str = "https://solana-rpc.publicnode.com";
        const GUN_URL: &str = "https://fra1.solanagun.com:8875/<TOKEN>";
        const RECIPIENT_ADDRESS: &str = "<RECIPIENT_ADDRESS>";
        const AMOUNT_LAMPORTS: u64 = 1_000_000;

        #[tokio::main]
        async fn main() -> anyhow::Result<()> {
            let payer = read_keypair_file(KEYPAIR_PATH)
                .map_err(|error| anyhow::anyhow!(error.to_string()))?;
            let recipient: Pubkey = RECIPIENT_ADDRESS.parse()?;

            let rpc = RpcClient::new_with_timeout(RPC_URL.to_string(), Duration::from_secs(30));
            let (blockhash, _) = rpc
                .get_latest_blockhash_with_commitment(CommitmentConfig::confirmed())
                .await?;

            let instruction =
                system_instruction::transfer(&payer.pubkey(), &recipient, AMOUNT_LAMPORTS);
            let transaction = VersionedTransaction::from(Transaction::new_signed_with_payer(
                &[instruction],
                Some(&payer.pubkey()),
                &[&payer],
                blockhash,
            ));

            let gun = RpcClient::new_with_timeout(GUN_URL.to_string(), Duration::from_secs(30));
            let signature = gun
                .send_transaction_with_config(
                    &transaction,
                    RpcSendTransactionConfig { skip_preflight: true, ..Default::default() },
                )
                .await?;

            println!("Submitted. Transaction signature: {signature}");

            Ok(())
        }
        ```
      </Step>

      <Step title="Run">
        ```bash theme={"system"}
        cargo run --release
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

## Submission response

A successful call returns the transaction signature and means Solana Gun accepted it for forwarding.

<Note>
  It does not guarantee confirmation on Solana.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.