Files
smom-dbis-138/scripts/update-oracle-price.sh
2026-03-02 12:14:09 -08:00

280 lines
9.7 KiB
Bash
Executable File

#!/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"; }
# Load .env if available
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.." || exit 1
if [ -f .env ]; then
set -a
source .env
set +a
fi
# RPC URL priority: command arg > RPC_URL_138 > RPC_URL > working defaults
DEFAULT_RPC="http://192.168.11.211:8545"
RPC_URL="${1:-${RPC_URL_138:-${RPC_URL:-$DEFAULT_RPC}}}"
ORACLE_ADDRESS="${2:-0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6}"
AGGREGATOR_ADDRESS="${AGGREGATOR_ADDRESS:-0x99b3511a2d315a497c8112c1fdd8d508d4b1e506}"
PRIVATE_KEY="${3:-${PRIVATE_KEY:-${DEPLOYER_PRIVATE_KEY:-}}}"
# Test RPC and fallback if needed
if ! curl -s -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
--max-time 3 "$RPC_URL" > /dev/null 2>&1; then
log_warn "Primary RPC not accessible, trying alternatives..."
# Try alternative RPCs
for ALT_RPC in "http://192.168.11.211:8545" "https://rpc-http-pub.d-bis.org"; do
if curl -s -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
--max-time 3 "$ALT_RPC" > /dev/null 2>&1; then
log_info "Using alternative RPC: $ALT_RPC"
RPC_URL="$ALT_RPC"
break
fi
done
fi
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"
# Check if account is authorized transmitter
if [ -n "$PRIVATE_KEY" ]; then
DEPLOYER_ADDR=$(cast wallet address --private-key "$PRIVATE_KEY" 2>/dev/null || echo "")
if [ -n "$DEPLOYER_ADDR" ]; then
log_info "Checking transmitter authorization..."
IS_TRANSMITTER=$(timeout 10 cast call "$AGGREGATOR_ADDRESS" "isTransmitter(address)(bool)" "$DEPLOYER_ADDR" --rpc-url "$RPC_URL" 2>/dev/null || echo "false")
if [ "$IS_TRANSMITTER" != "true" ]; then
log_warn "Account $DEPLOYER_ADDR is NOT an authorized transmitter"
log_info "Oracle requires transmitter role to update prices"
log_info "Options:"
log_info " 1. Use Oracle Publisher service (VMID 3500) - recommended"
log_info " 2. Use an authorized transmitter account private key"
log_info " 3. Add this account as transmitter (requires admin)"
log_info ""
log_info "Checking for transmitter addresses..."
TX_COUNT=0
for i in 0 1 2 3 4 5; do
TX_ADDR=$(timeout 10 cast call "$AGGREGATOR_ADDRESS" "transmitters(uint256)(address)" "$i" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$TX_ADDR" ] && [ "$TX_ADDR" != "0x0000000000000000000000000000000000000000" ]; then
log_info " Transmitter $TX_COUNT: $TX_ADDR"
TX_COUNT=$((TX_COUNT + 1))
fi
done
if [ $TX_COUNT -eq 0 ]; then
log_error "No transmitters found - oracle may not be configured"
fi
exit 1
else
log_success "Account is authorized transmitter"
fi
fi
fi
# Use aggregator address for updates (proxy is read-only)
UPDATE_CONTRACT="$AGGREGATOR_ADDRESS"
log_info "Updating aggregator contract: $UPDATE_CONTRACT"
# Send transaction (with timeout)
log_info "Sending transaction to aggregator (this may take 30-60 seconds)..."
TX_OUTPUT=$(timeout 90 cast send "$UPDATE_CONTRACT" \
"$UPDATE_METHOD(uint256)" \
"$PRICE_DECIMALS" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 20000000000 \
2>&1)
# Check if transaction was sent
if [ $? -ne 0 ]; then
log_error "Transaction failed or timed out"
echo "$TX_OUTPUT"
exit 1
fi
# Extract transaction hash from output
TX_HASH=$(echo "$TX_OUTPUT" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}' || \
echo "$TX_OUTPUT" | grep -oE "0x[0-9a-fA-F]{64}" | head -1 || echo "")
# If still no hash, check for error messages
if [ -z "$TX_HASH" ]; then
if echo "$TX_OUTPUT" | grep -qi "error\|failed\|revert"; then
log_error "Transaction failed:"
echo "$TX_OUTPUT"
exit 1
elif echo "$TX_OUTPUT" | grep -qi "insufficient funds\|gas"; then
log_error "Transaction failed (gas/funds issue):"
echo "$TX_OUTPUT"
exit 1
else
log_warn "Could not extract transaction hash from output:"
echo "$TX_OUTPUT" | head -20
log_info "Transaction may have been sent - check explorer or try again"
exit 1
fi
fi
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 ""