Overview
The Dynamic Swift SDK provides wallet management functionality for Ethereum-based wallets. This guide covers the core wallet operations demonstrated in the sample application: creating wallets, checking balances, signing messages, and sending transactions.
Prerequisites
Wallet Creation
Create New Wallet Account
To create a new wallet for an authenticated user, use the createWalletAccount
function:
import DynamicSwiftSDK
let dynamicClient: DynamicClient
// Create a new wallet account
do {
let accountAddress = try await createWalletAccount(client: dynamicClient)
print("✅ Wallet created successfully!")
print("Account Address: \(accountAddress)")
// The wallet is automatically added to the user's verified credentials
} catch {
print("❌ Failed to create wallet: \(error)")
}
Wallet Initialization from Existing Address
Initialize Ethereum Wallet from Address
Once a wallet exists (either created or already present), you can initialize an EthereumWallet
instance:
import DynamicSwiftSDK
let dynamicClient: DynamicClient
let walletAddress = "0x1234567890abcdef1234567890abcdef12345678" // Existing wallet address
do {
let ethereumWallet = try EthereumWallet(
address: walletAddress,
client: dynamicClient
)
print("Wallet initialized: \(ethereumWallet.address.asString())")
} catch {
print("Failed to initialize wallet: \(error)")
}
Get Wallet from Verified Credentials
import DynamicSwiftSDK
let dynamicClient: DynamicClient
// Get user's verified credentials and filter for blockchain wallets
if let verifiedCredentials = dynamicClient.user?.verifiedCredentials {
for credential in verifiedCredentials {
if credential.oauthProvider == .blockchain,
let walletAddress = credential.publicIdentifier {
do {
let wallet = try EthereumWallet(address: walletAddress, client: dynamicClient)
print("Wallet found: \(wallet.address.asString())")
break
} catch {
print("Failed to initialize wallet: \(error)")
}
}
}
}
Get Wallet Address
let walletAddress = ethereumWallet.address.asString()
print("Wallet Address: \(walletAddress)")
// Get blockchain address for cross-chain compatibility
let blockchainAddress = ethereumWallet.accountAddress
print("Blockchain Address: \(blockchainAddress.asString())")
Get Wallet Properties
// Wallet address (used in sample app UI)
let walletAddress = ethereumWallet.address.asString()
print("Wallet Address: \(walletAddress)")
// Account address for cross-chain compatibility
let accountAddress = ethereumWallet.accountAddress.asString()
print("Account Address: \(accountAddress)")
Balance Management
Get Wallet Balance
// Get latest balance
do {
let balanceWei = try await ethereumWallet.getBalance(.Latest)
// Convert Wei to Ether
let etherValue = Double(String(balanceWei)) ?? 0.0
let balanceEth = etherValue / pow(10.0, 18.0)
print("Balance: \(String(format: "%.6f", balanceEth)) ETH")
} catch {
print("Failed to get balance: \(error)")
}
Switch to Sepolia Network
// Switch to Sepolia testnet (as used in sample app)
let sepoliaNetwork = SupportedEthereumNetwork.sepoliaTestnet.chainConfig
do {
try await ethereumWallet.switchNetwork(to: sepoliaNetwork)
let balance = try await ethereumWallet.getBalance(.Latest)
// Convert Wei to ETH (sample app pattern)
let etherValue = Double(String(balance)) ?? 0.0
let balanceEth = etherValue / pow(10.0, 18.0)
let formattedBalance = String(format: "%.6f", balanceEth)
print("Sepolia Balance: \(formattedBalance) ETH")
} catch {
print("Failed to switch network or get balance: \(error)")
}
Message Signing
Sign a Message
let message = "Hello There!" // Message used in sample app
do {
let signature = try await ethereumWallet.signMessage(message)
print("✅ Message signed successfully!")
print("📝 Message: \(message)")
print("🔏 Signature: \(signature)")
print("🔏 Address: \(ethereumWallet.accountAddress.asString())")
} catch {
print("❌ Failed to sign message: \(error)")
}
Verify Signature
import DynamicSwiftSDK
let message = "Hello There!"
let signature = "0x..." // Signature from signing step
let walletAddress = ethereumWallet.accountAddress.asString()
do {
let verificationResult = try verifySignature(
message: message,
signature: signature,
walletAddress: walletAddress
)
print("Verification Result: \(verificationResult)")
} catch {
print("Failed to verify signature: \(error)")
}
Transaction Management
Send ETH Transaction
// Transaction parameters (as used in sample app)
let amount = BigUInt(10000000000000000) // 0.01 ETH in wei
let recipient = EthereumAddress("0xd4f748199B91c22095150d2d4Cca3Fe6175B0CbA")
let chainId = SupportedEthereumNetwork.sepoliaTestnet.chainConfig.chainId
do {
// Get network client for Sepolia
let networkClient = try await ethereumWallet.getNetworkClient(for: chainId)
// Get current gas price and set gas limit
let gasPrice = try await networkClient.eth_gasPriceBigInt()
let gasLimit = BigUInt(21_000) // Standard ETH transfer
print("🌐 Network: Ethereum Sepolia (Chain ID: \(chainId))")
print("💰 Amount: 0.01 ETH")
print("📍 From: \(ethereumWallet.address.asString())")
print("📍 To: \(recipient.asString())")
print("⛽ Gas Price: \(gasPrice) wei")
print("⛽ Gas Limit: \(gasLimit)")
// Create transaction
let transaction = EthereumTransaction(
from: ethereumWallet.address,
to: recipient,
value: amount,
data: Data(),
nonce: nil,
gasPrice: gasPrice,
gasLimit: gasLimit,
chainId: chainId
)
print("📝 Transaction created successfully")
// Send transaction
let txHash = try await ethereumWallet.sendTransaction(transaction)
print("✅ Transaction sent!")
print("🔗 Transaction Hash: \(txHash)")
// Get network details for block explorer URL
if let supportedNetwork = SupportedEthereumNetwork.fromChainId(chainId) {
let networkConfig = supportedNetwork.chainConfig
if let explorerUrl = networkConfig.blockExplorerUrls.first {
print("🔍 View on \(networkConfig.name): \(explorerUrl)/tx/\(txHash)")
}
}
} catch {
print("❌ Transaction failed: \(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)")
Network Management
Sepolia Testnet
// Sepolia testnet configuration (used in sample app)
let sepoliaNetwork = SupportedEthereumNetwork.sepoliaTestnet.chainConfig
print("Sepolia Chain ID: \(sepoliaNetwork.chainId)") // 11155111
// Switch to Sepolia (sample app pattern)
do {
try await ethereumWallet.switchNetwork(to: sepoliaNetwork)
print("🌐 Switched to Ethereum Sepolia")
} catch {
print("❌ Failed to switch to Sepolia: \(error)")
}
Error Handling
Common Wallet Errors
do {
let wallet = try EthereumWallet(address: "invalid_address", client: dynamicClient)
} catch {
if let nsError = error as NSError? {
switch nsError.code {
case 1003:
print("Could not determine wallet ID from address")
default:
print("Wallet creation error: \(error)")
}
}
}
Best Practices
1. Network Switching
Always switch to Sepolia before performing operations:
// Switch to Sepolia first
let sepoliaNetwork = SupportedEthereumNetwork.sepoliaTestnet.chainConfig
try await wallet.switchNetwork(to: sepoliaNetwork)
// Then perform operations
let balance = try await wallet.getBalance(.Latest)
2. Gas Price Fetching
Get current gas prices for transactions:
let networkClient = try await wallet.getNetworkClient(for: chainId)
let gasPrice = try await networkClient.eth_gasPriceBigInt()