Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt

Use this file to discover all available pages before exploring further.

Overview

This guide covers sending SOL, building transactions, and signing transactions on Solana.

Prerequisites

Send SOL

import DynamicSDKSwift
import SolanaWeb3

let sdk = DynamicSDK.instance()

func sendSOL(
    wallet: BaseWallet,
    recipient: String,
    amountInSOL: Double
) async throws -> String {
    // Create connection and signer
    let connection = try sdk.solana.createConnection()
    let signer = sdk.solana.createSigner(wallet: wallet)

    // Get latest blockhash
    let blockhash = try await connection.getLatestBlockhash()

    // Convert SOL to lamports (1 SOL = 10^9 lamports)
    let lamports = UInt64(amountInSOL * 1_000_000_000)

    // Create versioned transfer transaction using the builder
    let transaction = try SolanaWeb3.SolanaTransactionBuilder.createVersionedTransferTransaction(
        from: wallet.address,
        to: recipient,
        lamports: lamports,
        recentBlockhash: blockhash.blockhash
    )

    // Sign and send
    return try await signer.signAndSendEncodedTransaction(
        base64Transaction: transaction.serializeToBase64()
    )
}
SolanaWeb3 Dependency: Add the SolanaWeb3 package from solana-mobile/SolanaSwift to build Solana transactions.

Sign Transaction

Sign a base64-encoded transaction without sending:
let sdk = DynamicSDK.instance()

func signTransaction(wallet: BaseWallet, base64Transaction: String) async throws -> String {
    let signer = sdk.solana.createSigner(wallet: wallet)
    return try await signer.signEncodedTransaction(base64Transaction: base64Transaction)
}

Sign and Send Pre-Built Transaction

If you already have a base64-encoded transaction:
let sdk = DynamicSDK.instance()

func signAndSendTransaction(wallet: BaseWallet, base64Transaction: String) async throws -> String {
    let signer = sdk.solana.createSigner(wallet: wallet)
    return try await signer.signAndSendEncodedTransaction(base64Transaction: base64Transaction)
}

Complete Send SOL View

import SwiftUI
import DynamicSDKSwift
import SolanaWeb3

struct SolanaSendView: View {
    let wallet: BaseWallet

    @State private var recipient = ""
    @State private var amount = ""
    @State private var signature: String?
    @State private var isLoading = false
    @State private var error: String?

    private let sdk = DynamicSDK.instance()

    var body: some View {
        VStack(spacing: 16) {
            Text("From: \(formatAddress(wallet.address))")
                .font(.caption)
                .foregroundColor(.secondary)

            TextField("Recipient Address", text: $recipient)
                .textFieldStyle(.roundedBorder)
                .autocapitalization(.none)

            TextField("Amount (SOL)", text: $amount)
                .textFieldStyle(.roundedBorder)
                .keyboardType(.decimalPad)

            Button("Send SOL") { sendTransaction() }
                .buttonStyle(.borderedProminent)
                .disabled(recipient.isEmpty || amount.isEmpty || isLoading)

            if isLoading {
                ProgressView("Sending...")
            }

            if let signature = signature {
                VStack(spacing: 8) {
                    Text("Success!")
                        .foregroundColor(.green)
                        .fontWeight(.semibold)

                    Text(signature)
                        .font(.caption)
                        .lineLimit(1)

                    Link("View on Explorer",
                         destination: URL(string: "https://explorer.solana.com/tx/\(signature)?cluster=devnet")!)
                        .font(.caption)
                }
                .padding()
                .background(Color.green.opacity(0.1))
                .cornerRadius(8)
            }

            if let error = error {
                Text(error)
                    .foregroundColor(.red)
                    .font(.caption)
            }
        }
        .padding()
        .navigationTitle("Send SOL")
    }

    private func formatAddress(_ address: String) -> String {
        "\(address.prefix(6))...\(address.suffix(4))"
    }

    private func sendTransaction() {
        guard let amountDouble = Double(amount) else {
            error = "Invalid amount"
            return
        }

        isLoading = true
        error = nil
        signature = nil

        Task { @MainActor in
            do {
                // Create connection and signer
                let connection = try sdk.solana.createConnection()
                let signer = sdk.solana.createSigner(wallet: wallet)

                // Get latest blockhash
                let blockhash = try await connection.getLatestBlockhash()

                // Convert SOL to lamports
                let lamports = UInt64(amountDouble * 1_000_000_000)

                // Create versioned transfer transaction using the builder
                let transaction = try SolanaWeb3.SolanaTransactionBuilder.createVersionedTransferTransaction(
                    from: wallet.address,
                    to: recipient,
                    lamports: lamports,
                    recentBlockhash: blockhash.blockhash
                )

                // Sign and send
                signature = try await signer.signAndSendEncodedTransaction(
                    base64Transaction: transaction.serializeToBase64()
                )
            } catch {
                self.error = error.localizedDescription
            }
            isLoading = false
        }
    }
}

Lamports Conversion

Solana uses lamports as its smallest unit (1 SOL = 10^9 lamports):
// Convert SOL to lamports
func solToLamports(_ sol: Double) -> UInt64 {
    return UInt64(sol * 1_000_000_000)
}

// Convert lamports to SOL
func lamportsToSol(_ lamports: UInt64) -> Double {
    return Double(lamports) / 1_000_000_000
}

// Usage
let amount = 1.5 // SOL
let lamports = solToLamports(amount)
print("\(amount) SOL = \(lamports) lamports")
func explorerURL(signature: String, cluster: String = "devnet") -> URL? {
    URL(string: "https://explorer.solana.com/tx/\(signature)?cluster=\(cluster)")
}

// Usage
if let url = explorerURL(signature: txSignature, cluster: "mainnet-beta") {
    // Open in browser or display link
}

Signer Methods

MethodDescription
createSigner(wallet:)Create a signer for a Solana wallet
signMessage(message:)Sign an arbitrary message
signEncodedTransaction(base64Transaction:)Sign a transaction without sending
signAndSendEncodedTransaction(base64Transaction:)Sign and broadcast a transaction

Error Handling

do {
    let signature = try await sendSOL(
        wallet: wallet,
        recipient: recipient,
        amountInSOL: 1.0
    )
} catch {
    let errorDesc = error.localizedDescription.lowercased()

    if errorDesc.contains("insufficient") {
        print("Insufficient balance")
    } else if errorDesc.contains("blockhash") {
        print("Blockhash expired, try again")
    } else {
        print("Transaction failed: \(error)")
    }
}

Devnet Faucet

For testing, get free devnet SOL from the Solana Faucet.

Next Steps