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 balance operations for both EVM and Solana chains, including balance retrieval, conversion utilities, and formatting.

Prerequisites

Get Wallet Balance

The SDK provides a unified method to get balance for any wallet type:
import DynamicSDKSwift

let sdk = DynamicSDK.instance()

func getBalance(wallet: BaseWallet) async {
    do {
        let balance = try await sdk.wallets.getBalance(wallet: wallet)
        print("Balance: \(balance)")
    } catch {
        print("Failed to get balance: \(error)")
    }
}

Display Balance with SwiftUI

import SwiftUI
import DynamicSDKSwift

@MainActor
class WalletBalanceViewModel: ObservableObject {
    @Published var balance: String?
    @Published var isLoading = false
    @Published var errorMessage: String?

    private let sdk = DynamicSDK.instance()

    func fetchBalance(wallet: BaseWallet) {
        isLoading = true
        errorMessage = nil

        Task {
            do {
                balance = try await sdk.wallets.getBalance(wallet: wallet)
            } catch {
                errorMessage = "Failed to get balance: \(error.localizedDescription)"
            }
            isLoading = false
        }
    }
}

struct WalletBalanceView: View {
    let wallet: BaseWallet
    @StateObject private var viewModel = WalletBalanceViewModel()

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Text("Balance")
                .font(.caption)
                .foregroundColor(.secondary)

            if viewModel.isLoading {
                HStack {
                    ProgressView()
                    Text("Loading...")
                        .foregroundColor(.secondary)
                }
            } else if let balance = viewModel.balance {
                Text(balance)
                    .font(.headline)
            } else if let error = viewModel.errorMessage {
                Text(error)
                    .foregroundColor(.red)
                    .font(.caption)
            }
        }
        .onAppear {
            viewModel.fetchBalance(wallet: wallet)
        }
    }
}

EVM Balance Conversions

Wei to ETH Conversion

import BigInt

/// Convert Wei to ETH
func weiToEth(_ wei: BigUInt, decimals: Int = 6) -> String {
    let etherValue = Double(String(wei)) ?? 0.0
    let ethValue = etherValue / pow(10.0, 18.0)
    return String(format: "%.\(decimals)f", ethValue)
}

// Usage
let balanceWei: BigUInt = 1500000000000000000 // 1.5 ETH
let balanceEth = weiToEth(balanceWei)
print("Balance: \(balanceEth) ETH")

ETH to Wei Conversion

import BigInt

/// Convert ETH to Wei
func ethToWei(_ eth: Double) -> BigUInt {
    let weiValue = eth * pow(10.0, 18.0)
    return BigUInt(weiValue)
}

// Usage
let ethAmount = 1.5
let weiAmount = ethToWei(ethAmount)
print("\(ethAmount) ETH = \(weiAmount) Wei")

Gwei Conversions

import BigInt

/// Convert Wei to Gwei
func weiToGwei(_ wei: BigUInt) -> Double {
    let gweiValue = Double(String(wei)) ?? 0.0
    return gweiValue / pow(10.0, 9.0) // 1 Gwei = 10^9 Wei
}

/// Convert Gwei to Wei
func gweiToWei(_ gwei: Double) -> BigUInt {
    let weiValue = gwei * pow(10.0, 9.0)
    return BigUInt(weiValue)
}

// Usage for gas prices
let gasPriceGwei = 50.0
let gasPriceWei = gweiToWei(gasPriceGwei)
print("Gas Price: \(gasPriceGwei) Gwei = \(gasPriceWei) Wei")

Balance Formatting

import BigInt

/// Format EVM balance with appropriate units
func formatEvmBalance(_ wei: BigUInt) -> String {
    let ethValue = Double(String(wei)) ?? 0.0
    let eth = ethValue / pow(10.0, 18.0)

    if eth >= 1.0 {
        return String(format: "%.4f ETH", eth)
    } else if eth >= 0.001 {
        return String(format: "%.6f ETH", eth)
    } else {
        let gwei = ethValue / pow(10.0, 9.0)
        return String(format: "%.2f Gwei", gwei)
    }
}

Solana Balance Conversions

Solana uses lamports as its smallest unit, where 1 SOL = 10^9 lamports (9 decimal places).

Lamports to SOL Conversion

/// Convert lamports to SOL
func lamportsToSol(_ lamports: UInt64, decimals: Int = 6) -> String {
    let solValue = Double(lamports) / 1_000_000_000.0
    return String(format: "%.\(decimals)f", solValue)
}

// Usage
let balanceLamports: UInt64 = 1_500_000_000 // 1.5 SOL
let balanceSol = lamportsToSol(balanceLamports)
print("Balance: \(balanceSol) SOL")

SOL to Lamports Conversion

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

// Usage
let solAmount = 1.5
let lamportsAmount = solToLamports(solAmount)
print("\(solAmount) SOL = \(lamportsAmount) lamports")

SOL Balance Formatting

/// Format SOL balance for display
func formatSolBalance(_ lamports: UInt64) -> String {
    let sol = Double(lamports) / 1_000_000_000.0

    if sol >= 1.0 {
        return String(format: "%.4f SOL", sol)
    } else if sol >= 0.001 {
        return String(format: "%.6f SOL", sol)
    } else {
        return String(format: "%.9f SOL", sol)
    }
}

Multi-Chain Balance Display

Handle balances for both EVM and Solana wallets:
import DynamicSDKSwift

let sdk = DynamicSDK.instance()

func displayBalance(wallet: BaseWallet) async {
    do {
        let balance = try await sdk.wallets.getBalance(wallet: wallet)
        let chain = wallet.chain.uppercased()

        switch chain {
        case "EVM":
            print("Balance: \(balance) (in Wei)")
        case "SOL":
            print("Balance: \(balance) (in lamports)")
        default:
            print("Balance: \(balance)")
        }
    } catch {
        print("Failed to get balance: \(error)")
    }
}

// Display all wallet balances
func displayAllBalances() async {
    for wallet in sdk.wallets.userWallets {
        print("\(wallet.chain) wallet: \(wallet.address)")
        await displayBalance(wallet: wallet)
    }
}

Conversion Helper Class

import BigInt

/// Helper class for balance conversions
struct BalanceConverter {
    /// EVM conversions
    static func weiToEth(_ wei: BigUInt) -> Double {
        let ethValue = Double(String(wei)) ?? 0.0
        return ethValue / pow(10.0, 18.0)
    }

    static func ethToWei(_ eth: Double) -> BigUInt {
        return BigUInt(eth * pow(10.0, 18.0))
    }

    static func weiToGwei(_ wei: BigUInt) -> Double {
        let gweiValue = Double(String(wei)) ?? 0.0
        return gweiValue / pow(10.0, 9.0)
    }

    /// Solana conversions
    static func lamportsToSol(_ lamports: UInt64) -> Double {
        return Double(lamports) / 1_000_000_000.0
    }

    static func solToLamports(_ sol: Double) -> UInt64 {
        return UInt64(sol * 1_000_000_000)
    }

    /// Format for display
    static func formatBalance(
        value: String,
        chain: String,
        decimals: Int = 4
    ) -> String {
        switch chain.uppercased() {
        case "EVM":
            if let wei = BigUInt(value) {
                let eth = weiToEth(wei)
                return String(format: "%.\(decimals)f ETH", eth)
            }
        case "SOL":
            if let lamports = UInt64(value) {
                let sol = lamportsToSol(lamports)
                return String(format: "%.\(decimals)f SOL", sol)
            }
        default:
            break
        }
        return value
    }
}

// Usage
let formatted = BalanceConverter.formatBalance(
    value: "1500000000000000000",
    chain: "EVM",
    decimals: 4
)
print(formatted) // "1.5000 ETH"

Common Token Decimals

ChainTokenDecimalsUnit
EVMETH18Wei
EVMUSDC6Smallest unit
EVMUSDT6Smallest unit
EVMWBTC8Smallest unit
SolanaSOL9Lamports

Best Practices

1. Cache Balances

@MainActor
class BalanceCache: ObservableObject {
    @Published var balances: [String: String] = [:]

    private let sdk = DynamicSDK.instance()

    func refreshBalance(for wallet: BaseWallet) async {
        do {
            let balance = try await sdk.wallets.getBalance(wallet: wallet)
            balances[wallet.address] = balance
        } catch {
            print("Failed to refresh balance: \(error)")
        }
    }

    func refreshAllBalances() async {
        for wallet in sdk.wallets.userWallets {
            await refreshBalance(for: wallet)
        }
    }
}

2. Handle Precision

// Use BigUInt for EVM to avoid precision loss
import BigInt

let wei = BigUInt("1500000000000000000")! // 1.5 ETH
let eth = BalanceConverter.weiToEth(wei)

// Use UInt64 for Solana
let lamports: UInt64 = 1_500_000_000 // 1.5 SOL
let sol = BalanceConverter.lamportsToSol(lamports)

3. Refresh After Transactions

func sendTransactionAndRefresh(wallet: BaseWallet) async {
    do {
        // Send transaction
        let txHash = try await sendTransaction(wallet: wallet)

        // Wait a moment for blockchain confirmation
        try await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds

        // Refresh balance
        let newBalance = try await sdk.wallets.getBalance(wallet: wallet)
        print("New balance: \(newBalance)")
    } catch {
        print("Error: \(error)")
    }
}

Next Steps