Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
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: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:/// 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
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
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
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: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
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
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
// 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
// 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
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
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