#!/usr/bin/env bash # Update Oracle Contract with Current ETH/USD Price # This script fetches the current ETH price from CoinGecko and updates the oracle contract # Usage: ./scripts/update-oracle-price.sh [rpc-url] [oracle-address] [private-key] set -euo pipefail # 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"; } RPC_URL="${1:-https://rpc-http-pub.d-bis.org}" ORACLE_ADDRESS="${2:-0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6}" PRIVATE_KEY="${3:-${DEPLOYER_PRIVATE_KEY:-}}" if [ -z "$PRIVATE_KEY" ]; then log_error "Private key required" log_info "Usage: $0 [rpc-url] [oracle-address] [private-key]" log_info " OR: Set DEPLOYER_PRIVATE_KEY environment variable" exit 1 fi echo "=========================================" echo "Update Oracle Price Feed" echo "=========================================" echo "" log_info "RPC URL: $RPC_URL" log_info "Oracle Address: $ORACLE_ADDRESS" echo "" # Check RPC connectivity log_info "Checking RPC connectivity..." if ! curl -s -X POST -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \ "$RPC_URL" >/dev/null 2>&1; then log_error "RPC is not accessible at $RPC_URL" exit 1 fi log_success "RPC is accessible" # Fetch current ETH price from CoinGecko log_info "Fetching ETH/USD price from CoinGecko..." ETH_PRICE=$(curl -s 'https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd' | \ python3 -c "import sys, json; data = json.load(sys.stdin); print(data.get('ethereum', {}).get('usd', '0'))" 2>/dev/null || echo "0") if [ "$ETH_PRICE" = "0" ] || [ -z "$ETH_PRICE" ]; then log_error "Failed to fetch ETH price from CoinGecko" log_info "Trying Binance API as fallback..." ETH_PRICE=$(curl -s 'https://api.binance.com/api/v3/ticker/price?symbol=ETHUSDT' | \ python3 -c "import sys, json; data = json.load(sys.stdin); print(data.get('price', '0'))" 2>/dev/null || echo "0") fi if [ "$ETH_PRICE" = "0" ] || [ -z "$ETH_PRICE" ]; then log_error "Failed to fetch ETH price from all sources" exit 1 fi log_success "ETH/USD Price: \$$ETH_PRICE" # Convert to 8 decimals (oracle format) PRICE_DECIMALS=$(python3 << PYEOF price = float("$ETH_PRICE") decimals = int(price * 100000000) print(decimals) PYEOF ) log_info "Price in 8 decimals: $PRICE_DECIMALS" echo "" # Check current oracle price log_info "Checking current oracle price..." CURRENT_ORACLE_DATA=$(cast call "$ORACLE_ADDRESS" \ "latestRoundData()" \ --rpc-url "$RPC_URL" 2>/dev/null || echo "") if [ -n "$CURRENT_ORACLE_DATA" ] && [ "$CURRENT_ORACLE_DATA" != "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ]; then # Parse current price CURRENT_ANSWER=$(echo "$CURRENT_ORACLE_DATA" | cut -c 131-194) # Extract answer field CURRENT_PRICE=$(python3 << PYEOF answer_hex = "$CURRENT_ANSWER" answer_int = int(answer_hex, 16) # Handle negative (if signed) if answer_int > 2**255: answer_int = answer_int - 2**256 price = answer_int / 100000000 print(price) PYEOF ) log_info "Current oracle price: \$$(printf '%.2f' $CURRENT_PRICE)" # Check if update is needed (only update if difference > 1%) PRICE_DIFF=$(python3 << PYEOF current = float("$CURRENT_PRICE") new = float("$ETH_PRICE") diff = abs(new - current) / current * 100 print(diff) PYEOF ) if (( $(echo "$PRICE_DIFF < 1" | bc -l) )); then log_warn "Price difference is less than 1% (${PRICE_DIFF}%)" log_info "Skipping update to save gas" exit 0 fi fi # Update oracle contract log_info "Updating oracle contract..." log_info "This will send a transaction to update the price feed..." # Check if updateAnswer function exists, if not try transmit if cast sig "updateAnswer(int256)" >/dev/null 2>&1; then UPDATE_METHOD="updateAnswer" elif cast sig "transmit(int256)" >/dev/null 2>&1; then UPDATE_METHOD="transmit" else log_error "Could not determine oracle update method" log_info "Please check the oracle contract ABI" exit 1 fi log_info "Using method: $UPDATE_METHOD" # Send transaction TX_HASH=$(cast send "$ORACLE_ADDRESS" \ "$UPDATE_METHOD(int256)" \ "$PRICE_DECIMALS" \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --json 2>/dev/null | python3 -c "import sys, json; print(json.load(sys.stdin).get('transactionHash', ''))" || echo "") if [ -z "$TX_HASH" ]; then log_error "Failed to send transaction" exit 1 fi log_success "Transaction sent: $TX_HASH" # Wait for confirmation log_info "Waiting for transaction confirmation..." sleep 5 # Verify update log_info "Verifying oracle update..." NEW_ORACLE_DATA=$(cast call "$ORACLE_ADDRESS" \ "latestRoundData()" \ --rpc-url "$RPC_URL" 2>/dev/null || echo "") if [ -n "$NEW_ORACLE_DATA" ]; then NEW_ANSWER=$(echo "$NEW_ORACLE_DATA" | cut -c 131-194) NEW_PRICE=$(python3 << PYEOF answer_hex = "$NEW_ANSWER" answer_int = int(answer_hex, 16) if answer_int > 2**255: answer_int = answer_int - 2**256 price = answer_int / 100000000 print(price) PYEOF ) log_success "Oracle updated successfully!" log_info "New oracle price: \$$(printf '%.2f' $NEW_PRICE)" else log_warn "Could not verify oracle update (may need more time for confirmation)" fi echo "" log_success "=========================================" log_success "Oracle Price Update Complete!" log_success "=========================================" echo ""