Overview
This guide covers gas price estimation, gas limit calculation, and optimization strategies for EVM transactions using the web3dart package.Prerequisites
- Dynamic SDK initialized (see Installation Guide)
- Basic understanding of EVM transactions
dynamic_sdk_web3dartpackage installed
Get Current Gas Price
Fetch the current gas price from the network:Copy
Ask AI
import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:dynamic_sdk_web3dart/dynamic_sdk_web3dart.dart';
import 'package:web3dart/web3dart.dart';
final sdk = DynamicSDK.instance;
Future<BigInt?> getGasPrice(int chainId) async {
try {
final client = sdk.web3dart.createPublicClient(chainId: chainId);
final gasPrice = await client.getGasPrice();
return gasPrice.getValueInUnitBI(EtherUnit.wei);
} catch (e) {
print('Failed to get gas price: $e');
return null;
}
}
Standard Gas Limits
Use these standard gas limits for common transaction types:Copy
Ask AI
/// Common gas limits for different transaction types
class GasLimits {
/// Standard ETH transfer: 21,000 gas
static const int ethTransfer = 21000;
/// ERC-20 token transfer: 65,000 gas
static const int erc20Transfer = 65000;
/// ERC-20 approve: 50,000 gas
static const int erc20Approve = 50000;
/// Contract deployment: 500,000+ gas (varies by contract)
static const int contractDeploy = 500000;
/// Contract function call: 100,000 gas (estimate first)
static const int contractCall = 100000;
/// NFT minting: 150,000 gas (varies by contract)
static const int nftMint = 150000;
}
// Usage
final transaction = Transaction(
from: EthereumAddress.fromHex(wallet.address),
to: EthereumAddress.fromHex(recipientAddress),
value: EtherAmount.inWei(BigInt.from(amountInWei)),
gasPrice: EtherAmount.inWei(gasPrice),
maxGas: GasLimits.ethTransfer,
);
EIP-1559 Gas Pricing
EIP-1559 introduced a new gas pricing mechanism with two components:Understanding EIP-1559 Parameters
Copy
Ask AI
class EIP1559Gas {
/// Base fee: Algorithmically determined by the network
/// This is burned and adjusts based on network congestion
final BigInt baseFeePerGas;
/// Priority fee (tip): Goes to the miner/validator
/// Higher tips get faster inclusion
final BigInt maxPriorityFeePerGas;
/// Max fee: Maximum you're willing to pay per gas
/// Should be: baseFee + maxPriorityFee + buffer
final BigInt maxFeePerGas;
EIP1559Gas({
required this.baseFeePerGas,
required this.maxPriorityFeePerGas,
required this.maxFeePerGas,
});
}
Setting Gas Prices
Copy
Ask AI
Future<EIP1559Gas> calculateGasPrices(int chainId) async {
final client = sdk.web3dart.createPublicClient(chainId: chainId);
// Get current base fee
final gasPrice = await client.getGasPrice();
final baseFee = gasPrice.getValueInUnitBI(EtherUnit.wei);
// Set priority fee (tip)
final priorityFee = baseFee ~/ BigInt.from(2); // Typically 50% of base fee
// Set max fee (with 2x buffer for volatility)
final maxFee = baseFee * BigInt.from(2) + priorityFee;
return EIP1559Gas(
baseFeePerGas: baseFee,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: maxFee,
);
}
// Usage
final gasPrices = await calculateGasPrices(1);
final transaction = Transaction(
from: EthereumAddress.fromHex(wallet.address),
to: EthereumAddress.fromHex(recipient),
value: EtherAmount.inWei(BigInt.from(amount)),
maxGas: 21000,
maxFeePerGas: EtherAmount.inWei(gasPrices.maxFeePerGas),
maxPriorityFeePerGas: EtherAmount.inWei(gasPrices.maxPriorityFeePerGas),
);
Gas Optimization Strategies
Choose Optimal Gas Prices
Copy
Ask AI
class GasStrategy {
/// Low priority: Base fee + minimal tip
static EIP1559Gas slow(BigInt baseFee) {
return EIP1559Gas(
baseFeePerGas: baseFee,
maxPriorityFeePerGas: BigInt.from(1000000000), // 1 Gwei
maxFeePerGas: baseFee + BigInt.from(1000000000),
);
}
/// Medium priority: Base fee + standard tip
static EIP1559Gas standard(BigInt baseFee) {
final priorityFee = baseFee ~/ BigInt.from(2);
return EIP1559Gas(
baseFeePerGas: baseFee,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: baseFee * BigInt.from(2) + priorityFee,
);
}
/// High priority: Base fee + high tip
static EIP1559Gas fast(BigInt baseFee) {
final priorityFee = baseFee;
return EIP1559Gas(
baseFeePerGas: baseFee,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: baseFee * BigInt.from(3) + priorityFee,
);
}
}
// Usage
final client = sdk.web3dart.createPublicClient(chainId: 1);
final gasPrice = await client.getGasPrice();
final baseFee = gasPrice.getValueInUnitBI(EtherUnit.wei);
// Choose strategy based on urgency
final gas = GasStrategy.fast(baseFee);
Gas Cost Calculator
Calculate the total cost of a transaction:Copy
Ask AI
class GasCostCalculator {
/// Calculate transaction cost in Wei
static BigInt calculateCost({
required int gasLimit,
required BigInt maxFeePerGas,
}) {
return BigInt.from(gasLimit) * maxFeePerGas;
}
/// Calculate transaction cost in ETH
static double calculateCostInETH({
required int gasLimit,
required BigInt maxFeePerGas,
}) {
final costWei = calculateCost(
gasLimit: gasLimit,
maxFeePerGas: maxFeePerGas,
);
return costWei.toDouble() / 1e18;
}
/// Calculate transaction cost in USD (given ETH price)
static double calculateCostInUSD({
required int gasLimit,
required BigInt maxFeePerGas,
required double ethPriceUSD,
}) {
final costETH = calculateCostInETH(
gasLimit: gasLimit,
maxFeePerGas: maxFeePerGas,
);
return costETH * ethPriceUSD;
}
}
// Usage
final gasLimit = 21000;
final maxFeePerGas = BigInt.from(50000000000); // 50 Gwei
final costETH = GasCostCalculator.calculateCostInETH(
gasLimit: gasLimit,
maxFeePerGas: maxFeePerGas,
);
print('Transaction cost: $costETH ETH');
final costUSD = GasCostCalculator.calculateCostInUSD(
gasLimit: gasLimit,
maxFeePerGas: maxFeePerGas,
ethPriceUSD: 2000,
);
print('Transaction cost: \$$costUSD USD');
Gas Price Display Widget
Copy
Ask AI
import 'package:flutter/material.dart';
import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:dynamic_sdk_web3dart/dynamic_sdk_web3dart.dart';
import 'package:web3dart/web3dart.dart';
class GasPriceWidget extends StatefulWidget {
final int chainId;
const GasPriceWidget({Key? key, required this.chainId}) : super(key: key);
@override
State<GasPriceWidget> createState() => _GasPriceWidgetState();
}
class _GasPriceWidgetState extends State<GasPriceWidget> {
final sdk = DynamicSDK.instance;
BigInt? currentGasPrice;
String? recommendation;
@override
void initState() {
super.initState();
_updateGasPrice();
}
Future<void> _updateGasPrice() async {
try {
final client = sdk.web3dart.createPublicClient(chainId: widget.chainId);
final gasPrice = await client.getGasPrice();
final priceWei = gasPrice.getValueInUnitBI(EtherUnit.wei);
final priceGwei = priceWei.toDouble() / 1e9;
setState(() {
currentGasPrice = priceWei;
// 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 (e) {
print('Failed to update gas price: $e');
}
}
@override
Widget build(BuildContext context) {
final priceGwei = currentGasPrice != null
? (currentGasPrice!.toDouble() / 1e9)
: null;
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Text(
'Gas Price',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const Spacer(),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _updateGasPrice,
),
],
),
const SizedBox(height: 8),
if (priceGwei != null) ...[
Row(
children: [
Text(
'${priceGwei.toStringAsFixed(2)} Gwei',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 8),
if (priceGwei < 20)
const Icon(Icons.check_circle, color: Colors.green)
else if (priceGwei < 50)
const Icon(Icons.warning, color: Colors.orange)
else
const Icon(Icons.error, color: Colors.red),
],
),
if (recommendation != null) ...[
const SizedBox(height: 4),
Text(
recommendation!,
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
] else
const CircularProgressIndicator(),
],
),
);
}
}
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
class ChainGasDefaults {
static Map<String, int> getDefaults(int chainId) {
switch (chainId) {
case 1: // Ethereum
return {'gasLimit': 21000, 'priorityFee': 2000000000}; // 2 Gwei
case 137: // Polygon
return {'gasLimit': 21000, 'priorityFee': 30000000000}; // 30 Gwei
case 10: // Optimism
case 8453: // Base
return {'gasLimit': 21000, 'priorityFee': 1000000}; // 0.001 Gwei
case 42161: // Arbitrum
return {'gasLimit': 21000, 'priorityFee': 1000000}; // 0.001 Gwei
default:
return {'gasLimit': 21000, 'priorityFee': 1000000000}; // 1 Gwei
}
}
}
Best Practices
1. Always Add a Buffer
Copy
Ask AI
// Add 10-20% buffer to gas estimates
int addGasBuffer(int estimatedGas, {double bufferPercentage = 20}) {
return (estimatedGas * (1 + bufferPercentage / 100)).toInt();
}
// Usage
final gasWithBuffer = addGasBuffer(21000, bufferPercentage: 20);
2. Set Reasonable Max Fees
Copy
Ask AI
// Don't set maxFeePerGas too low, or transaction may fail
Future<BigInt> calculateSafeMaxFee(int chainId) async {
final client = sdk.web3dart.createPublicClient(chainId: chainId);
final gasPrice = await client.getGasPrice();
final baseFee = gasPrice.getValueInUnitBI(EtherUnit.wei);
return baseFee * BigInt.from(2); // At least 2x base fee
}
3. Monitor Gas Prices
Copy
Ask AI
Future<bool> shouldWaitForBetterGas(int chainId, {double thresholdGwei = 100}) async {
try {
final client = sdk.web3dart.createPublicClient(chainId: chainId);
final gasPrice = await client.getGasPrice();
final priceGwei = gasPrice.getValueInUnitBI(EtherUnit.wei).toDouble() / 1e9;
if (priceGwei > thresholdGwei) {
print('Gas prices are high ($priceGwei Gwei). Consider waiting.');
return true;
}
return false;
} catch (e) {
print('Failed to check gas price: $e');
return false;
}
}
4. Handle Gas Errors
Copy
Ask AI
Future<String?> sendTransactionWithGasHandling({
required BaseWallet wallet,
required Transaction transaction,
}) async {
try {
return await DynamicSDK.instance.web3dart.sendTransaction(
transaction: transaction,
wallet: wallet,
);
} catch (e) {
if (e.toString().contains('gas')) {
print('Gas estimation failed - try increasing gas limit');
}
return null;
}
}
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