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

# Send a Solana v1 transaction

> Build and send a Solana v1 SOL transfer with the Phantom browser extension

Send a Solana v1 SOL transfer with the Phantom browser extension.

## Send SOL

Call `runExample(rpcUrl, recipient)` from a button handler to send 0.001 SOL on devnet.

<Accordion title="Transaction example">
  <CodeGroup>
    ```typescript title="usage.ts" theme={null}
    import { connectPhantom } from "./connect";
    import { sendV1Transfer } from "./transaction";

    export async function runExample(rpcUrl: string, recipient: string) {
      try {
        const session = await connectPhantom("solana:devnet");
        const signature = await sendV1Transfer(session, rpcUrl, recipient);
        console.log("Submitted:", signature);
        return signature;
      } catch (error) {
        console.error("Transfer failed:", error);
        throw error;
      }
    }
    ```

    ```typescript title="transaction.ts" theme={null}
    import * as solana from "@solana/kit";
    import { getTransferSolInstruction } from "@solana-program/system";
    import { SolanaSignTransaction } from "@solana/wallet-standard-features";
    import type { PhantomSession, SolanaChain } from "./connect";

    const genesisHashes = {
      "solana:devnet": "EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG",
      "solana:mainnet": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d",
    };

    export async function prepareV1Transfer(
      rpcUrl: string, sender: string, recipient: string, amount: bigint,
      chain: SolanaChain = "solana:devnet",
    ) {
      if (amount <= 0n) throw new Error("Enter a positive amount in lamports.");
      const rpc = solana.createSolanaRpc(rpcUrl);
      if (await rpc.getGenesisHash().send() !== genesisHashes[chain]) {
        throw new Error(`RPC endpoint does not match ${chain}.`);
      }
      const { value: lifetime } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send();
      const message = solana.pipe(
        solana.createTransactionMessage({ version: 1 }),
        (message) => solana.setTransactionMessageFeePayer(solana.address(sender), message),
        (message) => solana.setTransactionMessageLifetimeUsingBlockhash(lifetime, message),
        (message) => solana.setTransactionMessageConfig({
          computeUnitLimit: 200_000,
          loadedAccountsDataSizeLimit: 1_048_576,
          priorityFeeLamports: 1_000n, // Total priority fee in lamports.
        }, message),
        (message) => solana.appendTransactionMessageInstruction(getTransferSolInstruction({
          source: solana.createNoopSigner(solana.address(sender)),
          destination: solana.address(recipient), amount,
        }), message),
      );
      const transaction = solana.compileTransaction(message);
      const { value: simulation } = await rpc.simulateTransaction(
        solana.getBase64EncodedWireTransaction(transaction),
        { encoding: "base64", commitment: "confirmed", sigVerify: false },
      ).send();
      if (simulation.err) throw new Error("Simulation failed.", { cause: simulation.err });
      const bytes = new Uint8Array(solana.getTransactionEncoder().encode(transaction));
      return { rpc, bytes, simulation };
    }

    export async function sendV1Transfer(
      session: PhantomSession, rpcUrl: string,
      recipient: string, amount = 1_000_000n, chain: SolanaChain = "solana:devnet",
    ) {
      const { wallet, account } = session;
      if (!account.chains.includes(chain)) throw new Error("Account does not support this network.");
      const { rpc, bytes } = await prepareV1Transfer(rpcUrl, account.address, recipient, amount, chain);
      if (!wallet.accounts.includes(account)) throw new Error("Wallet account changed. Reconnect.");
      const [result] = await wallet.features[SolanaSignTransaction].signTransaction({
        account, chain, transaction: bytes,
      });
      if (!result) throw new Error("Phantom did not return a signed transaction.");
      const signed = solana.getTransactionDecoder().decode(result.signedTransaction);
      const signature = solana.getSignatureFromTransaction(signed);
      try {
        await rpc.sendTransaction(solana.getBase64EncodedWireTransaction(signed), {
          encoding: "base64", preflightCommitment: "confirmed", skipPreflight: false,
        }).send();
      } catch (cause) {
        throw Object.assign(new Error(`Check ${signature} before retrying.`, { cause }), { signature });
      }
      return signature;
    }
    ```
  </CodeGroup>
</Accordion>

<Accordion title="Installation and connection">
  ```bash theme={null}
  npm install @solana/kit@8.3.0 @solana-program/system@0.15.0 \
    @solana/wallet-standard-features@1.5.0 @wallet-standard/app@1.1.1 \
    @wallet-standard/base@1.1.0 @wallet-standard/features@1.1.0
  ```

  Save `connect.ts`, `usage.ts`, and `transaction.ts` in the same directory.

  ```typescript title="connect.ts" theme={null}
  import { getWallets } from "@wallet-standard/app";
  import { StandardConnect, type StandardConnectFeature } from "@wallet-standard/features";
  import { SolanaSignTransaction, type SolanaSignTransactionFeature } from "@solana/wallet-standard-features";
  import type { Wallet } from "@wallet-standard/base";

  export type PhantomWallet = Wallet & {
    features: StandardConnectFeature & SolanaSignTransactionFeature;
  };

  export type SolanaChain = "solana:devnet" | "solana:mainnet";

  export async function connectPhantom(chain: SolanaChain) {
    const wallet = getWallets().get().find((wallet) => wallet.name === "Phantom");
    if (!wallet?.features[StandardConnect] || !wallet.features[SolanaSignTransaction]) {
      throw new Error("Install the Phantom browser extension, then reload.");
    }
    const phantom = wallet as PhantomWallet;
    const { accounts } = await phantom.features[StandardConnect].connect();
    const account = accounts.find((account) => account.chains.includes(chain));
    if (!account) throw new Error("Connect a Phantom account on the selected network.");
    return { wallet: phantom, account };
  }

  export type PhantomSession = Awaited<ReturnType<typeof connectPhantom>>;
  ```
</Accordion>

## V1 settings

V1 stores resource limits and the priority fee in the message configuration. This transfer uses 200,000 compute units, a 1 MiB loaded account data limit, and a total priority fee of 1,000 lamports. Re-estimate these values when you change the instructions.

The example verifies that the RPC endpoint matches the selected network, simulates before requesting approval, then submits the transaction Phantom returns with preflight enabled. Preserve the wallet's changes when submitting.

## Confirm the transaction

A signature indicates submission. Wait for `confirmed` or `finalized` status and check for execution errors before showing success. To read the transaction, set `maxSupportedTransactionVersion: 1` in `getTransaction` and check that the returned `version` is `1`.

If submission or confirmation is uncertain, check the existing signature before retrying. Submission errors from this example include a `signature` property. Phantom may refresh the blockhash during signing, so expiry of the original blockhash does not prove failure.

## Next steps

* [Solana v1 transaction requirements](https://solana.com/upgrades/larger-transaction-sizes#sending-v1-transactions)
* [Resolve transaction simulation warnings](/recipes/transactions/resolve-transaction-simulation-warnings)
