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

# Send Solana Transactions

> Send SOL and SPL token transactions in Unity.

<Note>
  **Requires** `xyz.dynamic.unitysdk.solana` package and `com.solana.unity_sdk` for transaction building. Message signing works without these packages.
</Note>

## Sign message

Message signing works without the Solana extension package:

```csharp theme={"system"}
string signature = await DynamicSDK.Instance.Networks.Solana.SignMessage(
    wallet.Id, "Hello World");
```

## Send SOL (versioned transaction)

```csharp theme={"system"}
using Solana.Unity.Programs;
using Solana.Unity.Rpc.Models;
using Solana.Unity.Wallet;

var solana = DynamicSDK.Instance.Networks.Solana;
var rpcClient = solana.CreateConnection();

// Get recent blockhash
var blockHashResult = await rpcClient.GetLatestBlockHashAsync();
var blockHash = blockHashResult.Result.Value.Blockhash;

var fromKey = new PublicKey(wallet.Address);
var toKey = new PublicKey("RecipientAddress");
var lamports = (ulong)(0.01 * 1_000_000_000); // 0.01 SOL

// Build versioned (v0) transaction
var tx = new VersionedTransaction
{
    RecentBlockHash = blockHash,
    FeePayer = fromKey,
    Instructions = new List<TransactionInstruction>
    {
        SystemProgram.Transfer(fromKey, toKey, lamports)
    },
    AddressTableLookups = new List<MessageAddressTableLookup>()
};

var message = tx.CompileMessage();

// Prepend 1 empty signature slot for the SDK to sign
var txBytes = new byte[1 + 64 + message.Length];
txBytes[0] = 1; // 1 signature slot (compact-u16)
// bytes 1..64 stay zero (empty signature placeholder)
Buffer.BlockCopy(message, 0, txBytes, 65, message.Length);

string txHash = await solana.SignAndSendTransaction(
    wallet.Id, txBytes, SolanaTransactionType.Versioned);
```

## Send SPL token (versioned transaction)

```csharp theme={"system"}
using Solana.Unity.Programs;
using Solana.Unity.Rpc.Models;
using Solana.Unity.Wallet;

var solana = DynamicSDK.Instance.Networks.Solana;
var rpcClient = solana.CreateConnection();

var blockHashResult = await rpcClient.GetLatestBlockHashAsync();
var blockHash = blockHashResult.Result.Value.Blockhash;

var ownerKey = new PublicKey(wallet.Address);
var recipientKey = new PublicKey("RecipientAddress");
var mintKey = new PublicKey("TokenMintAddress"); // e.g. USDC mint

// Derive Associated Token Accounts
var sourceAta = AssociatedTokenAccountProgram
    .DeriveAssociatedTokenAccount(ownerKey, mintKey);
var destAta = AssociatedTokenAccountProgram
    .DeriveAssociatedTokenAccount(recipientKey, mintKey);

int decimals = 6; // USDC has 6 decimals
var rawAmount = (ulong)(1.5 * Math.Pow(10, decimals)); // 1.5 USDC

var tx = new VersionedTransaction
{
    RecentBlockHash = blockHash,
    FeePayer = ownerKey,
    Instructions = new List<TransactionInstruction>
    {
        // Create destination ATA if it doesn't exist (idempotent)
        AssociatedTokenAccountProgram.CreateAssociatedTokenAccount(
            ownerKey, recipientKey, mintKey),
        // Transfer SPL tokens
        TokenProgram.Transfer(sourceAta, destAta, rawAmount, ownerKey)
    },
    AddressTableLookups = new List<MessageAddressTableLookup>()
};

var message = tx.CompileMessage();

var txBytes = new byte[1 + 64 + message.Length];
txBytes[0] = 1;
Buffer.BlockCopy(message, 0, txBytes, 65, message.Length);

string txHash = await solana.SignAndSendTransaction(
    wallet.Id, txBytes, SolanaTransactionType.Versioned);
```

## Common token mint addresses

| Token | Network       | Mint Address                                   |
| ----- | ------------- | ---------------------------------------------- |
| USDC  | Mainnet (101) | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` |
| USDC  | Devnet (103)  | `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` |

## Complete example

```csharp theme={"system"}
using DynamicSDK.Core;
using Solana.Unity.Programs;
using Solana.Unity.Rpc.Models;
using Solana.Unity.Wallet;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;

public class SolanaTransactionManager : MonoBehaviour
{
    private BaseWallet _solWallet;
    
    private void Start()
    {
        _solWallet = DynamicSDK.Instance.Wallets.UserWallets
            .FirstOrDefault(w => w.Chain.ToUpper() == "SOL");
    }
    
    public async void SendSol(string toAddress, double amount)
    {
        if (_solWallet == null)
        {
            Debug.LogError("No Solana wallet available");
            return;
        }
        
        try
        {
            var solana = DynamicSDK.Instance.Networks.Solana;
            var rpcClient = solana.CreateConnection();
            
            var blockHashResult = await rpcClient.GetLatestBlockHashAsync();
            var blockHash = blockHashResult.Result.Value.Blockhash;
            
            var fromKey = new PublicKey(_solWallet.Address);
            var toKey = new PublicKey(toAddress);
            var lamports = (ulong)(amount * 1_000_000_000);
            
            var tx = new VersionedTransaction
            {
                RecentBlockHash = blockHash,
                FeePayer = fromKey,
                Instructions = new List<TransactionInstruction>
                {
                    SystemProgram.Transfer(fromKey, toKey, lamports)
                },
                AddressTableLookups = new List<MessageAddressTableLookup>()
            };
            
            var message = tx.CompileMessage();
            var txBytes = new byte[1 + 64 + message.Length];
            txBytes[0] = 1;
            Buffer.BlockCopy(message, 0, txBytes, 65, message.Length);
            
            string txHash = await solana.SignAndSendTransaction(
                _solWallet.Id, txBytes, SolanaTransactionType.Versioned);
            
            Debug.Log($"Transaction sent: {txHash}");
        }
        catch (Exception ex)
        {
            Debug.LogError($"Transaction failed: {ex.Message}");
        }
    }
    
    public async void SignMessage(string message)
    {
        if (_solWallet == null)
        {
            Debug.LogError("No Solana wallet available");
            return;
        }
        
        string signature = await DynamicSDK.Instance.Networks.Solana.SignMessage(
            _solWallet.Id, message);
        
        Debug.Log($"Signature: {signature}");
    }
}
```

## Next steps

* [Message Signing](/docs/unity/wallets/solana/message-signing) - Sign messages with Solana wallets
* [Token Balances](/docs/unity/wallets/general/token-balances) - Query token balances
