Skip to main content

Overview

This guide covers basic wallet operations including balance management, message signing, and typed data signing with the Dynamic Swift SDK.

Prerequisites

Balance Management

Get Wallet Balance

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)")
    }
}

Get Balance with UI Updates

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)
        }
    }
}

Get Current Network

Get Wallet’s Current Network

import DynamicSDKSwift

let sdk = DynamicSDK.instance()

func getCurrentNetwork(wallet: BaseWallet) async {
    do {
        let network = try await sdk.wallets.getNetwork(wallet: wallet)
        print("Current network: \(network)")
    } catch {
        print("Failed to get network: \(error)")
    }
}

Display Network Information

import DynamicSDKSwift

@MainActor
class WalletNetworkViewModel: ObservableObject {
    @Published var networkDescription: String?
    @Published var isLoading = false
    
    private let sdk = DynamicSDK.instance()
    
    func fetchNetwork(wallet: BaseWallet) {
        isLoading = true
        
        Task {
            do {
                let network = try await sdk.wallets.getNetwork(wallet: wallet)
                networkDescription = resolveNetworkDisplay(
                    wallet: wallet,
                    networkValue: network
                )
            } catch {
                print("Failed to get network: \(error)")
            }
            isLoading = false
        }
    }
    
    private func resolveNetworkDisplay(wallet: BaseWallet, networkValue: Any) -> String {
        let chain = wallet.chain.uppercased()
        
        if chain == "EVM" {
            // Look up network name from available EVM networks
            if let match = sdk.networks.evm.first(where: { 
                String(describing: $0.chainId.value) == String(describing: networkValue) 
            }) {
                return "\(match.name) (chainId: \(match.chainId.value))"
            }
            return "Chain ID: \(networkValue)"
        }
        
        if chain == "SOL" {
            // Look up network name from available Solana networks
            if let match = sdk.networks.solana.first(where: { 
                String(describing: $0.networkId.value) == String(describing: networkValue) 
            }) {
                return match.name
            }
            return String(describing: networkValue)
        }
        
        return String(describing: networkValue)
    }
}

Message Signing

Sign a Message

import DynamicSDKSwift

let sdk = DynamicSDK.instance()

func signMessage(wallet: BaseWallet, message: String) async {
    do {
        let signature = try await sdk.wallets.signMessage(
            wallet: wallet,
            message: message
        )
        print("Message signed successfully!")
        print("Signature: \(signature)")
    } catch {
        print("Failed to sign message: \(error)")
    }
}

Complete Sign Message Example

import SwiftUI
import DynamicSDKSwift

struct SignMessageView: View {
    let wallet: BaseWallet
    
    @State private var message = ""
    @State private var signature: String?
    @State private var isLoading = false
    @State private var errorMessage: String?
    
    private let sdk = DynamicSDK.instance()
    
    var body: some View {
        VStack(spacing: 16) {
            TextField("Enter message to sign", text: $message)
                .textFieldStyle(.roundedBorder)
            
            Button("Sign Message") {
                signMessage()
            }
            .disabled(message.isEmpty || isLoading)
            
            if isLoading {
                ProgressView()
            }
            
            if let signature = signature {
                VStack(alignment: .leading, spacing: 8) {
                    Text("Signature:")
                        .font(.caption)
                        .foregroundColor(.secondary)
                    
                    Text(signature)
                        .font(.system(.caption, design: .monospaced))
                        .lineLimit(4)
                        .truncationMode(.middle)
                    
                    Button("Copy") {
                        UIPasteboard.general.string = signature
                    }
                    .font(.caption)
                }
                .padding()
                .background(Color(.systemGray6))
                .cornerRadius(8)
            }
            
            if let error = errorMessage {
                Text(error)
                    .foregroundColor(.red)
                    .font(.caption)
            }
        }
        .padding()
    }
    
    private func signMessage() {
        isLoading = true
        errorMessage = nil
        signature = nil
        
        Task { @MainActor in
            do {
                signature = try await sdk.wallets.signMessage(
                    wallet: wallet,
                    message: message
                )
            } catch {
                errorMessage = "Failed to sign: \(error.localizedDescription)"
            }
            isLoading = false
        }
    }
}

Sign Typed Data (EIP-712)

For EVM wallets, you can sign typed data following the EIP-712 standard:
import DynamicSDKSwift

let sdk = DynamicSDK.instance()

func signTypedData(wallet: BaseWallet) async {
    // Example EIP-712 typed data
    let typedDataJson = """
    {
        "types": {
            "EIP712Domain": [
                {"name": "name", "type": "string"},
                {"name": "version", "type": "string"},
                {"name": "chainId", "type": "uint256"}
            ],
            "Message": [
                {"name": "content", "type": "string"}
            ]
        },
        "primaryType": "Message",
        "domain": {
            "name": "Example App",
            "version": "1",
            "chainId": 1
        },
        "message": {
            "content": "Hello, World!"
        }
    }
    """
    
    do {
        let signature = try await sdk.wallets.signTypedData(
            wallet: wallet,
            typedDataJson: typedDataJson
        )
        print("Typed data signed!")
        print("Signature: \(signature)")
    } catch {
        print("Failed to sign typed data: \(error)")
    }
}

Complete Sign Typed Data Example

import SwiftUI
import DynamicSDKSwift

struct SignTypedDataView: View {
    let wallet: BaseWallet
    
    @State private var signature: String?
    @State private var isLoading = false
    @State private var errorMessage: String?
    
    private let sdk = DynamicSDK.instance()
    
    private let exampleTypedData = """
    {
        "types": {
            "EIP712Domain": [
                {"name": "name", "type": "string"},
                {"name": "version", "type": "string"},
                {"name": "chainId", "type": "uint256"}
            ],
            "Mail": [
                {"name": "from", "type": "string"},
                {"name": "to", "type": "string"},
                {"name": "contents", "type": "string"}
            ]
        },
        "primaryType": "Mail",
        "domain": {
            "name": "Example DApp",
            "version": "1",
            "chainId": 1
        },
        "message": {
            "from": "Alice",
            "to": "Bob",
            "contents": "Hello!"
        }
    }
    """
    
    var body: some View {
        VStack(spacing: 16) {
            Text("EIP-712 Typed Data")
                .font(.headline)
            
            Text(exampleTypedData)
                .font(.system(.caption2, design: .monospaced))
                .padding()
                .background(Color(.systemGray6))
                .cornerRadius(8)
            
            Button("Sign Typed Data") {
                signTypedData()
            }
            .disabled(isLoading)
            
            if isLoading {
                ProgressView()
            }
            
            if let signature = signature {
                VStack(alignment: .leading) {
                    Text("Signature:")
                        .font(.caption)
                    Text(signature)
                        .font(.system(.caption2, design: .monospaced))
                        .lineLimit(3)
                }
                .padding()
                .background(Color.green.opacity(0.1))
                .cornerRadius(8)
            }
            
            if let error = errorMessage {
                Text(error)
                    .foregroundColor(.red)
                    .font(.caption)
            }
        }
        .padding()
    }
    
    private func signTypedData() {
        isLoading = true
        errorMessage = nil
        signature = nil
        
        Task { @MainActor in
            do {
                signature = try await sdk.wallets.signTypedData(
                    wallet: wallet,
                    typedDataJson: exampleTypedData
                )
            } catch {
                errorMessage = "Failed to sign: \(error.localizedDescription)"
            }
            isLoading = false
        }
    }
}

Best Practices

1. Always Handle Errors

do {
    let balance = try await sdk.wallets.getBalance(wallet: wallet)
    // Use balance
} catch {
    // Show user-friendly error message
    print("Could not fetch balance. Please try again.")
}

2. Show Loading States

@Published var isLoading = false

func fetchBalance(wallet: BaseWallet) {
    isLoading = true
    Task {
        defer { isLoading = false }
        // ... fetch balance
    }
}

3. Refresh Data When Needed

struct WalletDetailsView: View {
    let wallet: BaseWallet
    @StateObject private var viewModel = WalletDetailsViewModel()
    
    var body: some View {
        // ... UI
        .onAppear {
            viewModel.refresh(wallet: wallet)
        }
        .refreshable {
            await viewModel.refreshAsync(wallet: wallet)
        }
    }
}

Next Steps

After mastering basic wallet operations, you can: