Overview
This guide covers sending ETH transactions including transaction creation, signing, and sending with the Dynamic Swift SDK.Prerequisites
- Dynamic SDK initialized (see Installation Guide)
- User authenticated (see Authentication Guide)
- Wallets available (see Wallet Creation)
- Network configured (see Networks)
Send ETH Transaction
Copy
Ask AI
import DynamicSDKSwift
import SwiftBigInt
let sdk = DynamicSDK.instance()
func sendTransaction(wallet: BaseWallet, to: String, amountInEth: Double) async {
do {
// Get current gas price
let chainId = 1 // Ethereum mainnet, or use your target chain
let client = sdk.evm.createPublicClient(chainId: chainId)
let gasPrice = try await client.getGasPrice()
// Convert ETH to Wei (1 ETH = 10^18 Wei)
let weiAmount = BigUInt(amountInEth * pow(10.0, 18.0))
// Create transaction
let transaction = EthereumTransaction(
from: wallet.address,
to: to,
value: weiAmount,
gas: BigUInt(21000), // Standard ETH transfer
maxFeePerGas: gasPrice * 2,
maxPriorityFeePerGas: gasPrice
)
// Send transaction
let txHash = try await sdk.evm.sendTransaction(
transaction: transaction,
wallet: wallet
)
print("Transaction sent!")
print("Hash: \(txHash)")
} catch {
print("Transaction failed: \(error)")
}
}
Complete Send Transaction Example
Copy
Ask AI
import SwiftUI
import DynamicSDKSwift
import SwiftBigInt
struct SendTransactionView: View {
let wallet: BaseWallet
@State private var recipient = ""
@State private var amount = ""
@State private var txHash: String?
@State private var isLoading = false
@State private var errorMessage: String?
private let sdk = DynamicSDK.instance()
var body: some View {
VStack(spacing: 16) {
TextField("Recipient address", text: $recipient)
.textFieldStyle(.roundedBorder)
.autocapitalization(.none)
TextField("Amount (ETH)", text: $amount)
.textFieldStyle(.roundedBorder)
.keyboardType(.decimalPad)
Button("Send Transaction") {
sendTransaction()
}
.disabled(recipient.isEmpty || amount.isEmpty || isLoading)
.buttonStyle(.borderedProminent)
if isLoading {
ProgressView("Sending...")
}
if let hash = txHash {
VStack(alignment: .leading, spacing: 8) {
Text("Transaction Sent!")
.font(.headline)
.foregroundColor(.green)
Text("Hash: \(hash)")
.font(.system(.caption, design: .monospaced))
.lineLimit(2)
Button("Copy Hash") {
UIPasteboard.general.string = hash
}
.font(.caption)
}
.padding()
.background(Color.green.opacity(0.1))
.cornerRadius(8)
}
if let error = errorMessage {
Text(error)
.foregroundColor(.red)
.font(.caption)
}
}
.padding()
}
private func sendTransaction() {
guard let amountDouble = Double(amount) else {
errorMessage = "Invalid amount"
return
}
isLoading = true
errorMessage = nil
txHash = nil
Task { @MainActor in
do {
// Convert ETH to Wei (1 ETH = 10^18 Wei)
let weiAmount = BigUInt(amountDouble * pow(10, 18))
// Get gas price
let chainId = 84532 // Base Sepolia - adjust as needed
let client = sdk.evm.createPublicClient(chainId: chainId)
let gasPrice = try await client.getGasPrice()
// Create and send transaction
let transaction = EthereumTransaction(
from: wallet.address,
to: recipient,
value: weiAmount,
gas: BigUInt(21000),
maxFeePerGas: gasPrice * 2,
maxPriorityFeePerGas: gasPrice
)
txHash = try await sdk.evm.sendTransaction(
transaction: transaction,
wallet: wallet
)
} catch {
errorMessage = "Failed: \(error.localizedDescription)"
}
isLoading = false
}
}
}
Sign Transaction (Without Sending)
To sign a transaction without broadcasting it:Copy
Ask AI
import DynamicSDKSwift
import SwiftBigInt
let sdk = DynamicSDK.instance()
func signTransaction(wallet: BaseWallet) async {
do {
let transaction = EthereumTransaction(
from: wallet.address,
to: "0x...",
value: BigUInt(1000000000000000), // 0.001 ETH in Wei
gas: BigUInt(21000),
maxFeePerGas: BigUInt(20000000000),
maxPriorityFeePerGas: BigUInt(1000000000)
)
// Sign without sending
let signedTx = try await sdk.evm.signTransaction(
transaction: transaction,
wallet: wallet
)
print("Signed transaction: \(signedTx)")
} catch {
print("Failed to sign: \(error)")
}
}
Best Practices
1. Always Get Current Gas Price
Copy
Ask AI
let client = sdk.evm.createPublicClient(chainId: chainId)
let gasPrice = try await client.getGasPrice()
// Add buffer for price fluctuations
let maxFeePerGas = gasPrice * 2
2. Handle Transaction Errors
Copy
Ask AI
do {
let txHash = try await sdk.evm.sendTransaction(
transaction: transaction,
wallet: wallet
)
} catch {
// Common errors:
// - Insufficient funds
// - Gas price too low
// - Invalid recipient address
// - Network issues
if error.localizedDescription.contains("insufficient") {
showError("Insufficient funds for transaction")
} else {
showError("Transaction failed: \(error.localizedDescription)")
}
}
3. Show Transaction Status
Copy
Ask AI
struct TransactionStatusView: View {
let txHash: String
let chainId: Int
var explorerUrl: String {
// Map chain ID to block explorer
switch chainId {
case 1: return "https://etherscan.io/tx/\(txHash)"
case 84532: return "https://sepolia.basescan.org/tx/\(txHash)"
case 137: return "https://polygonscan.com/tx/\(txHash)"
default: return ""
}
}
var body: some View {
VStack {
Text("Transaction Submitted")
.font(.headline)
Text(txHash)
.font(.caption)
.lineLimit(1)
.truncationMode(.middle)
if !explorerUrl.isEmpty {
Link("View on Explorer", destination: URL(string: explorerUrl)!)
.font(.caption)
}
}
}
}
4. Confirm Before Sending
Copy
Ask AI
struct ConfirmTransactionView: View {
let recipient: String
let amount: String
let onConfirm: () -> Void
let onCancel: () -> Void
var body: some View {
VStack(spacing: 16) {
Text("Confirm Transaction")
.font(.headline)
VStack(alignment: .leading) {
Text("To: \(recipient)")
Text("Amount: \(amount) ETH")
}
.font(.caption)
HStack {
Button("Cancel", action: onCancel)
.buttonStyle(.bordered)
Button("Confirm", action: onConfirm)
.buttonStyle(.borderedProminent)
}
}
.padding()
}
}
Error Handling
Common Transaction Errors
Copy
Ask AI
do {
let txHash = try await sdk.evm.sendTransaction(
transaction: transaction,
wallet: wallet
)
} catch {
let errorMessage: String
let errorDesc = error.localizedDescription.lowercased()
if errorDesc.contains("insufficient") {
errorMessage = "Insufficient balance for this transaction"
} else if errorDesc.contains("gas") {
errorMessage = "Gas estimation failed. Try increasing gas limit."
} else if errorDesc.contains("rejected") || errorDesc.contains("denied") {
errorMessage = "Transaction was rejected"
} else if errorDesc.contains("network") {
errorMessage = "Network error. Please check your connection."
} else {
errorMessage = "Transaction failed. Please try again."
}
showAlert(errorMessage)
}
Next Steps
- ERC-20 Token Transfers - Send ERC-20 tokens
- Smart Contract Interactions - Interact with smart contracts
- Gas Management - Gas estimation and optimization
- Message Signing - Sign messages and typed data