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()
)
}
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")
Transaction Explorer Links
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
| Method | Description |
|---|
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