Overview
This guide covers gas price estimation, gas limit calculation, and optimization strategies for EVM transactions.Prerequisites
- Dynamic SDK initialized (see Installation Guide)
- Basic understanding of EVM transactions
Get Current Gas Price
Fetch the current gas price from the network:Copy
Ask AI
import DynamicSDKSwift
let sdk = DynamicSDK.instance()
func getGasPrice(chainId: Int) async -> Int? {
do {
let client = sdk.evm.createPublicClient(chainId: chainId)
let gasPrice = try await client.getGasPrice()
return Int(gasPrice)
} catch {
print("Failed to get gas price: \(error)")
return nil
}
}
Standard Gas Limits
Use these standard gas limits for common transaction types:Copy
Ask AI
import SwiftBigInt
/// Common gas limits for different transaction types
struct GasLimits {
/// Standard ETH transfer: 21,000 gas
static let ethTransfer = 21_000
/// ERC-20 token transfer: 65,000 gas
static let erc20Transfer = 65_000
/// ERC-20 approve: 50,000 gas
static let erc20Approve = 50_000
/// Contract deployment: 500,000+ gas (varies by contract)
static let contractDeploy = 500_000
/// Contract function call: 100,000 gas (estimate first)
static let contractCall = 100_000
/// NFT minting: 150,000 gas (varies by contract)
static let nftMint = 150_000
}
// Usage
let transaction = EthereumTransaction(
from: wallet.address,
to: recipientAddress,
value: BigUInt(amountInWei),
gas: BigUInt(GasLimits.ethTransfer),
maxFeePerGas: gasPrice,
maxPriorityFeePerGas: priorityFee
)
Estimate Gas for Transactions
For complex contract interactions, estimate gas dynamically:Copy
Ask AI
import DynamicSDKSwift
let sdk = DynamicSDK.instance()
/// Estimate gas for a transaction
func estimateGas(
for transaction: EthereumTransaction,
chainId: Int
) async throws -> Int {
let client = sdk.evm.createPublicClient(chainId: chainId)
let estimate = try await client.estimateGas(transaction)
return Int(estimate.value)
}
/// Estimate gas with safety buffer
func estimateGasWithBuffer(
for transaction: EthereumTransaction,
chainId: Int,
bufferPercentage: Double = 20.0
) async throws -> Int {
let baseEstimate = try await estimateGas(for: transaction, chainId: chainId)
let buffer = 1.0 + (bufferPercentage / 100.0)
return Int(Double(baseEstimate) * buffer)
}
// Usage
let transaction = EthereumTransaction(
to: contractAddress,
data: calldata,
value: 0
)
let gasLimit = try await estimateGasWithBuffer(
for: transaction,
chainId: 1,
bufferPercentage: 20
)
EIP-1559 Gas Pricing
EIP-1559 introduced a new gas pricing mechanism with two components:Understanding EIP-1559 Parameters
Copy
Ask AI
struct EIP1559Gas {
/// Base fee: Algorithmically determined by the network
/// This is burned and adjusts based on network congestion
let baseFeePerGas: Int
/// Priority fee (tip): Goes to the miner/validator
/// Higher tips get faster inclusion
let maxPriorityFeePerGas: Int
/// Max fee: Maximum you're willing to pay per gas
/// Should be: baseFee + maxPriorityFee + buffer
let maxFeePerGas: Int
}
Setting Gas Prices
Copy
Ask AI
func calculateGasPrices(chainId: Int) async throws -> EIP1559Gas {
let client = sdk.evm.createPublicClient(chainId: chainId)
// Get current base fee
let gasPrice = try await client.getGasPrice()
let baseFee = Int(gasPrice.value)
// Set priority fee (tip)
let priorityFee = baseFee / 2 // Typically 50% of base fee
// Set max fee (with 2x buffer for volatility)
let maxFee = baseFee * 2 + priorityFee
return EIP1559Gas(
baseFeePerGas: baseFee,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: maxFee
)
}
// Usage
let gasPrices = try await calculateGasPrices(chainId: 1)
let transaction = EthereumTransaction(
from: wallet.address,
to: recipient,
value: BigUInt(amount),
gas: BigUInt(21000),
maxFeePerGas: BigUInt(gasPrices.maxFeePerGas),
maxPriorityFeePerGas: BigUInt(gasPrices.maxPriorityFeePerGas)
)
Gas Optimization Strategies
1. Batch Transactions
Instead of sending multiple transactions, batch them when possible:Copy
Ask AI
/// Example: Batch multiple token approvals
func batchApprovals(
wallet: BaseWallet,
tokenAddress: String,
spenders: [(address: String, amount: String)]
) async throws {
// Use a multicall contract to batch approvals
// This saves gas compared to individual transactions
}
2. Choose Optimal Gas Prices
Copy
Ask AI
struct GasStrategy {
/// Low priority: Base fee + minimal tip
static func slow(baseFee: Int) -> EIP1559Gas {
EIP1559Gas(
baseFeePerGas: baseFee,
maxPriorityFeePerGas: 1_000_000_000, // 1 Gwei
maxFeePerGas: baseFee + 1_000_000_000
)
}
/// Medium priority: Base fee + standard tip
static func standard(baseFee: Int) -> EIP1559Gas {
let priorityFee = baseFee / 2
EIP1559Gas(
baseFeePerGas: baseFee,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: baseFee * 2 + priorityFee
)
}
/// High priority: Base fee + high tip
static func fast(baseFee: Int) -> EIP1559Gas {
let priorityFee = baseFee
EIP1559Gas(
baseFeePerGas: baseFee,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: baseFee * 3 + priorityFee
)
}
}
// Usage
let client = sdk.evm.createPublicClient(chainId: 1)
let gasPrice = try await client.getGasPrice()
let baseFee = Int(gasPrice.value)
// Choose strategy based on urgency
let gas = GasStrategy.fast(baseFee: baseFee)
3. Monitor and Adjust Gas
Copy
Ask AI
@MainActor
class GasMonitor: ObservableObject {
@Published var currentGasPrice: Int?
@Published var recommendation: String?
private let sdk = DynamicSDK.instance()
private let chainId: Int
init(chainId: Int) {
self.chainId = chainId
}
func updateGasPrice() async {
do {
let client = sdk.evm.createPublicClient(chainId: chainId)
let gasPrice = try await client.getGasPrice()
let priceGwei = Double(gasPrice.value) / 1_000_000_000
currentGasPrice = Int(gasPrice.value)
// Provide recommendations
if priceGwei < 20 {
recommendation = "Low gas prices - good time to transact"
} else if priceGwei < 50 {
recommendation = "Moderate gas prices"
} else {
recommendation = "High gas prices - consider waiting"
}
} catch {
print("Failed to update gas price: \(error)")
}
}
}
Gas Cost Calculator
Calculate the total cost of a transaction:Copy
Ask AI
struct GasCostCalculator {
/// Calculate transaction cost in Wei
static func calculateCost(
gasLimit: Int,
maxFeePerGas: Int
) -> Int {
return gasLimit * maxFeePerGas
}
/// Calculate transaction cost in ETH
static func calculateCostInETH(
gasLimit: Int,
maxFeePerGas: Int
) -> Double {
let costWei = calculateCost(
gasLimit: gasLimit,
maxFeePerGas: maxFeePerGas
)
return Double(costWei) / 1_000_000_000_000_000_000
}
/// Calculate transaction cost in USD (given ETH price)
static func calculateCostInUSD(
gasLimit: Int,
maxFeePerGas: Int,
ethPriceUSD: Double
) -> Double {
let costETH = calculateCostInETH(
gasLimit: gasLimit,
maxFeePerGas: maxFeePerGas
)
return costETH * ethPriceUSD
}
}
// Usage
let gasLimit = 21_000
let maxFeePerGas = 50_000_000_000 // 50 Gwei
let costETH = GasCostCalculator.calculateCostInETH(
gasLimit: gasLimit,
maxFeePerGas: maxFeePerGas
)
print("Transaction cost: \(costETH) ETH")
let costUSD = GasCostCalculator.calculateCostInUSD(
gasLimit: gasLimit,
maxFeePerGas: maxFeePerGas,
ethPriceUSD: 2000
)
print("Transaction cost: $\(costUSD) USD")
Gas Price Display Component
Copy
Ask AI
import SwiftUI
struct GasPriceView: View {
@StateObject private var monitor: GasMonitor
init(chainId: Int) {
_monitor = StateObject(wrappedValue: GasMonitor(chainId: chainId))
}
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("Gas Price")
.font(.headline)
Spacer()
Button {
Task { await monitor.updateGasPrice() }
} label: {
Image(systemName: "arrow.clockwise")
}
}
if let gasPrice = monitor.currentGasPrice {
let priceGwei = Double(gasPrice) / 1_000_000_000
HStack {
Text("\(String(format: "%.2f", priceGwei)) Gwei")
.font(.title2)
.fontWeight(.bold)
if priceGwei < 20 {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
} else if priceGwei < 50 {
Image(systemName: "exclamationmark.circle.fill")
.foregroundColor(.orange)
} else {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.red)
}
}
if let recommendation = monitor.recommendation {
Text(recommendation)
.font(.caption)
.foregroundColor(.secondary)
}
} else {
ProgressView()
}
}
.padding()
.background(Color(.systemGray6))
.cornerRadius(8)
.onAppear {
Task { await monitor.updateGasPrice() }
}
}
}
Chain-Specific Gas Considerations
Ethereum Mainnet
- Base fee: Highly variable (10-100+ Gwei)
- Priority fee: 1-5 Gwei typically
- Peak times: Weekdays during US/EU business hours
Layer 2 Solutions
- Optimism/Arbitrum: ~0.001-0.01 Gwei
- Polygon: ~30-100 Gwei
- Base: ~0.001-0.01 Gwei
Copy
Ask AI
struct ChainGasDefaults {
static func getDefaults(for chainId: Int) -> (gasLimit: Int, priorityFee: Int) {
switch chainId {
case 1: // Ethereum
return (21_000, 2_000_000_000) // 2 Gwei priority
case 137: // Polygon
return (21_000, 30_000_000_000) // 30 Gwei priority
case 10, 8453: // Optimism, Base
return (21_000, 1_000_000) // 0.001 Gwei priority
case 42161: // Arbitrum
return (21_000, 1_000_000) // 0.001 Gwei priority
default:
return (21_000, 1_000_000_000) // 1 Gwei default
}
}
}
Best Practices
1. Always Add a Buffer
Copy
Ask AI
// Add 10-20% buffer to gas estimates
let estimatedGas = try await estimateGas(for: transaction, chainId: chainId)
let gasWithBuffer = Int(Double(estimatedGas) * 1.2)
2. Set Reasonable Max Fees
Copy
Ask AI
// Don't set maxFeePerGas too low, or transaction may fail
let baseFee = try await client.getGasPrice()
let maxFee = Int(baseFee.value) * 2 // At least 2x base fee
3. Monitor Gas Prices
Copy
Ask AI
// Check gas prices before important transactions
let gasPrice = try await client.getGasPrice()
let priceGwei = Double(gasPrice.value) / 1_000_000_000
if priceGwei > 100 {
showAlert("Gas prices are high. Consider waiting.")
}
4. Handle Gas Errors
Copy
Ask AI
do {
let txHash = try await sdk.evm.sendTransaction(
transaction: transaction,
wallet: wallet
)
} catch {
if error.localizedDescription.contains("gas") {
// Gas estimation failed - try increasing gas limit
print("Consider increasing gas limit")
}
}
Next Steps
- Send ETH Transactions - Apply gas management to ETH transfers
- ERC-20 Token Transfers - Optimize token transfer costs
- Smart Contract Interactions - Estimate gas for contract calls
- Networks - Understand different network gas costs