> ## 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.

# Token Balances

> Learn how to get wallet balances and work with balance conversions for EVM and Solana with the Dynamic Swift SDK.

## Overview

This guide covers balance operations for both EVM and Solana chains, including balance retrieval, conversion utilities, and formatting.

## Prerequisites

* Dynamic SDK initialized (see [Installation Guide](https://docs.dynamic.xyz/docs/swift/quickstart.md))
* User authenticated (see [Authentication Guide](https://docs.dynamic.xyz/docs/swift/authentication.md))
* Wallets available (see [Wallet Creation](https://docs.dynamic.xyz/docs/swift/wallet-creation.md))

## Multichain balances

Use `sdk.wallets.getMultichainBalances` to fetch token balances across multiple chains and networks in a single call. Use it for portfolio-style views instead of calling `getBalance` per wallet.

```swift theme={"system"}
import DynamicSDKSwift

let sdk = DynamicSDK.instance()

func getMultichainBalances(wallet: BaseWallet) async {
    let request = MultichainBalanceRequest(
        balanceRequests: [
            BalanceRequestItem(
                address: wallet.address,
                chain: .evm,
                networkIds: [1, 137, 56] // Ethereum, Polygon, BNB
            )
        ],
        filterSpamTokens: true
    )

    do {
        let response = try await sdk.wallets.getMultichainBalances(balanceRequest: request)
        for token in response.balances {
            print("\(token.symbol ?? ""): \(token.balanceDecimal ?? "")")
        }
    } catch {
        print("Failed to get balances: \(error)")
    }
}
```

`response.balances` is a flat list of `TokenBalance` items. Each item exposes `balance`, `balanceDecimal`, `symbol`, `name`, `decimals`, `networkId`, `chain`, `logoUrl`, and `isNative`.

## Get Wallet Balance

> [!NOTE]
>
> `getBalance` returns the native asset only (for example ETH on Ethereum, SOL on Solana) for the wallet's active network. For token balances across chains and networks, use `getMultichainBalances` above.

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

```swift theme={"system"}
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

```swift theme={"system"}
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

```swift theme={"system"}
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

```swift theme={"system"}
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

```swift theme={"system"}
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

```swift theme={"system"}
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

```swift theme={"system"}
/// 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

```swift theme={"system"}
/// 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

```swift theme={"system"}
/// 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:

```swift theme={"system"}
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

```swift theme={"system"}
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

| Chain | Token | Decimals | Unit |
| - | - | - | - |
| EVM | ETH | 18 | Wei |
| EVM | USDC | 6 | Smallest unit |
| EVM | USDT | 6 | Smallest unit |
| EVM | WBTC | 8 | Smallest unit |
| Solana | SOL | 9 | Lamports |

## Best Practices

### 1. Cache Balances

```swift theme={"system"}
@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

```swift theme={"system"}
// 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

```swift theme={"system"}
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

* [Send ETH Transactions](https://docs.dynamic.xyz/docs/swift/wallets/evm/send-eth.md) - Transfer ETH
* [Send Solana Transactions](https://docs.dynamic.xyz/docs/swift/wallets/solana/send-transactions.md) - Transfer SOL
* [Network Management](https://docs.dynamic.xyz/docs/swift/wallets/general/network-management.md) - Switch networks
* [ERC-20 Token Transfers](https://docs.dynamic.xyz/docs/swift/wallets/evm/erc20-transfers.md) - Send ERC-20 tokens


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.