#!/usr/bin/env bash # Send Transaction with Optimal Gas Pricing # Prevents stuck transactions by using dynamic gas pricing # Usage: ./send-with-optimal-gas.sh [args...] set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "$PROJECT_ROOT/scripts/lib/address-inventory.sh" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } load_explorer_runtime_env # Configuration RPC_URL="${RPC_URL_138:-http://192.168.11.250:8545}" GAS_MULTIPLIER="${GAS_MULTIPLIER:-1.5}" # Use 1.5x current gas for faster inclusion if [ -z "${PRIVATE_KEY:-}" ]; then log_error "PRIVATE_KEY not available in effective environment" exit 1 fi # Get optimal gas price (prefer Etherscan API, fallback to RPC) get_optimal_gas() { # Try Etherscan API first (if available) if [ -f "$SCRIPT_DIR/get-optimal-gas-from-api.sh" ]; then API_GAS=$("$SCRIPT_DIR/get-optimal-gas-from-api.sh" "proposed" 2>/dev/null || echo "") if [ -n "$API_GAS" ] && [ "$API_GAS" != "0" ]; then # Use API gas with multiplier for faster inclusion local optimal_gas=$(echo "scale=0; $API_GAS * $GAS_MULTIPLIER / 1" | bc 2>/dev/null || echo "$API_GAS") echo "$optimal_gas" return 0 fi fi # Fallback to RPC gas price local current_gas=$(cast gas-price --rpc-url "$RPC_URL" 2>/dev/null || echo "1000000000") local optimal_gas=$(echo "scale=0; $current_gas * $GAS_MULTIPLIER / 1" | bc 2>/dev/null || echo "$current_gas") echo "$optimal_gas" } # Check nonce check_nonce() { local account="$1" local current_nonce=$(cast nonce "$account" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") local pending_nonce=$(cast nonce "$account" --rpc-url "$RPC_URL" --pending 2>/dev/null || echo "$current_nonce") if [ "$pending_nonce" -gt "$current_nonce" ]; then local pending_count=$((pending_nonce - current_nonce)) log_warn "Found $pending_count pending transaction(s)" log_info "Current nonce: $current_nonce, Pending nonce: $pending_nonce" return 1 fi return 0 } # Get account address ACCOUNT=$(cast wallet address "$PRIVATE_KEY" 2>/dev/null || echo "") if [ -z "$ACCOUNT" ]; then log_error "Could not derive address from PRIVATE_KEY" exit 1 fi # Check nonce before sending log_info "Checking nonce..." if ! check_nonce "$ACCOUNT"; then log_warn "Pending transactions detected" log_info "Waiting 10 seconds for pending transactions..." sleep 10 # Re-check if ! check_nonce "$ACCOUNT"; then log_error "Still have pending transactions" log_info "Consider waiting longer or using higher gas price to replace" exit 1 fi fi # Get optimal gas price CURRENT_GAS=$(cast gas-price --rpc-url "$RPC_URL" 2>/dev/null || echo "1000000000") OPTIMAL_GAS=$(get_optimal_gas) CURRENT_GAS_GWEI=$(echo "scale=2; $CURRENT_GAS / 1000000000" | bc 2>/dev/null || echo "1") OPTIMAL_GAS_GWEI=$(echo "scale=2; $OPTIMAL_GAS / 1000000000" | bc 2>/dev/null || echo "1.5") log_info "Current gas price: $CURRENT_GAS_GWEI gwei" log_info "Optimal gas price: $OPTIMAL_GAS_GWEI gwei (${GAS_MULTIPLIER}x multiplier)" log_info "" # Get current nonce CURRENT_NONCE=$(cast nonce "$ACCOUNT" --rpc-url "$RPC_URL" 2>/dev/null || echo "0") log_info "Using nonce: $CURRENT_NONCE" log_info "" # Build cast send command CONTRACT="$1" FUNCTION="$2" shift 2 ARGS="$@" log_info "Sending transaction..." log_info " Contract: $CONTRACT" log_info " Function: $FUNCTION" log_info " Args: $ARGS" log_info "" # Send transaction with optimal gas TX_OUTPUT=$(cast send "$CONTRACT" "$FUNCTION" $ARGS \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --gas-price "$OPTIMAL_GAS" \ --nonce "$CURRENT_NONCE" \ 2>&1 || echo "FAILED") if echo "$TX_OUTPUT" | grep -qE "(blockHash|transactionHash)"; then TX_HASH=$(echo "$TX_OUTPUT" | grep -oE "(blockHash|transactionHash)[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}' | head -1) log_success "Transaction sent successfully!" log_info " Hash: $TX_HASH" log_info " Gas Price: $OPTIMAL_GAS_GWEI gwei" log_info " Nonce: $CURRENT_NONCE" exit 0 else log_error "Transaction failed" log_error "$TX_OUTPUT" # Check for specific errors if echo "$TX_OUTPUT" | grep -q "underpriced"; then log_warn "Transaction underpriced" log_info "Try with higher gas multiplier: GAS_MULTIPLIER=2.0 $0 $@" elif echo "$TX_OUTPUT" | grep -q "nonce"; then log_warn "Nonce issue detected" log_info "Wait for pending transactions or use next nonce" fi exit 1 fi