Overview

This guide covers wallet security features including private key management and key shares recovery with the Dynamic Swift SDK.

Prerequisites

Private Key Management

Export Private Key

Export the wallet’s private key for backup or migration purposes:
do {
    let privateKey = try await ethereumWallet.exportPrivateKey()
    print("✅ Private key exported successfully!")
    print("🔑 Private Key: \(privateKey)")

    // Note: Store securely and clear from memory after use
} catch {
    print("❌ Failed to export private key: \(error)")
}

Key Shares Management

Check Key Shares Availability

func checkKeySharesAvailability(client: DynamicClient, walletAddress: String) -> Bool {
    let keyShares = loadKeyShares(client: client, accountAddress: walletAddress)
    return keyShares != nil
}

// Usage
let hasKeyShares = checkKeySharesAvailability(
    client: dynamicClient,
    walletAddress: ethereumWallet.address.asString()
)

print("Key shares available: \(hasKeyShares)")

Recover Key Shares

Recover encrypted backup for a wallet using key share IDs:
private func recoverKeyshare(for credential: JwtVerifiedCredential) async {
    let walletId = credential.id

    guard let keyShareIds = getKeyShareIds(credential: credential) else {
        print("❌ No keyshare IDs found")
        return
    }

    do {
        let backup = try await recoverEncryptedBackupByWallet(
            client: dynamicClient,
            walletId: walletId,
            keyShareIds: keyShareIds,
            address: ethereumWallet.address.asString()
        )

        print("✅ Keyshare recovered successfully!")
        print("Backup: \(backup)")

    } catch {
        print("❌ Recovery failed: \(error)")
    }
}

Security Best Practices

1. Private Key Security

  • Never store private keys in plain text
  • Implement auto-clear for sensitive data
  • Use secure storage for backup data
  • Validate all user inputs before processing

2. Memory Management

// Clear sensitive data from memory after use
privateKey = nil
keyShares = nil

// Use secure enclave when available
if SecureEnclave.isAvailable {
    // Store sensitive data in secure enclave
}

3. Input Validation

// Always validate wallet addresses
func isValidEthereumAddress(_ address: String) -> Bool {
    let pattern = "^0x[a-fA-F0-9]{40}$"
    let regex = try! NSRegularExpression(pattern: pattern)
    let range = NSRange(location: 0, length: address.utf16.count)
    return regex.firstMatch(in: address, range: range) != nil
}

// Validate before processing
guard isValidEthereumAddress(walletAddress) else {
    print("❌ Invalid wallet address format")
    return
}

4. Secure Storage

// Use Keychain for sensitive data storage
import Security

func storePrivateKeySecurely(_ privateKey: String, for walletAddress: String) {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: walletAddress,
        kSecValueData as String: privateKey.data(using: .utf8)!,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
    ]
    
    SecItemAdd(query as CFDictionary, nil)
}

Error Handling

do {
    let privateKey = try await ethereumWallet.exportPrivateKey()
} catch {
    if let nsError = error as NSError? {
        switch nsError.code {
        case 1001:
            print("Access denied - authentication required")
        case 1002:
            print("Private key not available")
        case 1003:
            print("Security validation failed")
        default:
            print("Security error: \(error)")
        }
    }
}

Next Steps

After implementing wallet security, you can: