Files
proxmox/scripts/update-all-oracle-prices.sh
defiQUG cb47cce074 Complete markdown files cleanup and organization
- Organized 252 files across project
- Root directory: 187 → 2 files (98.9% reduction)
- Moved configuration guides to docs/04-configuration/
- Moved troubleshooting guides to docs/09-troubleshooting/
- Moved quick start guides to docs/01-getting-started/
- Moved reports to reports/ directory
- Archived temporary files
- Generated comprehensive reports and documentation
- Created maintenance scripts and guides

All files organized according to established standards.
2026-01-06 01:46:25 -08:00

297 lines
10 KiB
Bash
Executable File

#!/usr/bin/env bash
# Update All Oracle Contracts with Current Token Prices
# This script reads the token list and updates oracle contracts for all tokens
# Usage: ./scripts/update-all-oracle-prices.sh [rpc-url] [private-key]
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
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"; }
log_detail() { echo -e "${CYAN}[DETAIL]${NC} $1"; }
RPC_URL="${1:-https://rpc-http-pub.d-bis.org}"
PRIVATE_KEY="${2:-${DEPLOYER_PRIVATE_KEY:-}}"
if [ -z "$PRIVATE_KEY" ]; then
log_error "Private key required"
log_info "Usage: $0 [rpc-url] [private-key]"
log_info " OR: Set DEPLOYER_PRIVATE_KEY environment variable"
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
TOKEN_LIST_FILE="${TOKEN_LIST_FILE:-$PROJECT_ROOT/token-lists/lists/dbis-138.tokenlist.json}"
if [ ! -f "$TOKEN_LIST_FILE" ]; then
log_error "Token list file not found: $TOKEN_LIST_FILE"
exit 1
fi
echo "========================================="
echo "Update All Oracle Prices"
echo "========================================="
echo ""
log_info "RPC URL: $RPC_URL"
log_info "Token List: $TOKEN_LIST_FILE"
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"
echo ""
# Parse token list and map tokens to CoinGecko IDs
# Token mapping: symbol -> coingecko_id
declare -A TOKEN_MAP=(
["ETH"]="ethereum"
["WETH"]="ethereum" # WETH tracks ETH price
["WETH10"]="ethereum" # WETH10 tracks ETH price
["LINK"]="chainlink"
["ETH-USD"]="ethereum" # Oracle contract for ETH/USD
)
# Map of oracle addresses (token symbol -> aggregator address)
# Note: Updates go to the aggregator, but dApps read from the proxy
# Aggregator: 0x99b3511a2d315a497c8112c1fdd8d508d4b1e506 (for updates)
# Proxy: 0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6 (for reading)
declare -A ORACLE_ADDRESSES=(
["ETH-USD"]="0x99b3511a2d315a497c8112c1fdd8d508d4b1e506" # Aggregator address for updates
["ETH"]="0x99b3511a2d315a497c8112c1fdd8d508d4b1e506"
["WETH"]="0x99b3511a2d315a497c8112c1fdd8d508d4b1e506" # Uses ETH/USD oracle
["WETH10"]="0x99b3511a2d315a497c8112c1fdd8d508d4b1e506" # Uses ETH/USD oracle
# ["LINK-USD"]="0x..." # Would need separate oracle contract
)
# Extract tokens from token list
TOKENS=$(jq -r '.tokens[] | select(.tags[]? | contains("oracle") or contains("pricefeed")) | "\(.symbol)|\(.address)|\(.name)"' "$TOKEN_LIST_FILE" 2>/dev/null || echo "")
if [ -z "$TOKENS" ]; then
log_warn "No oracle/pricefeed tokens found in token list"
log_info "Looking for all tokens..."
TOKENS=$(jq -r '.tokens[] | "\(.symbol)|\(.address)|\(.name)"' "$TOKEN_LIST_FILE" 2>/dev/null || echo "")
fi
if [ -z "$TOKENS" ]; then
log_error "Could not parse tokens from token list"
exit 1
fi
# Build list of unique CoinGecko IDs to fetch
COINGECKO_IDS=()
while IFS='|' read -r SYMBOL ADDRESS NAME; do
if [ -z "$SYMBOL" ]; then continue; fi
COINGECKO_ID="${TOKEN_MAP[$SYMBOL]}"
if [ -n "$COINGECKO_ID" ] && [[ ! " ${COINGECKO_IDS[@]} " =~ " ${COINGECKO_ID} " ]]; then
COINGECKO_IDS+=("$COINGECKO_ID")
fi
done <<< "$TOKENS"
if [ ${#COINGECKO_IDS[@]} -eq 0 ]; then
log_error "No valid CoinGecko IDs found for tokens"
exit 1
fi
log_info "Tokens to update: ${COINGECKO_IDS[*]}"
echo ""
# Fetch prices from CoinGecko
log_info "Fetching prices from CoinGecko..."
COINGECKO_IDS_CSV=$(IFS=,; echo "${COINGECKO_IDS[*]}")
PRICES_JSON=$(curl -s "https://api.coingecko.com/api/v3/simple/price?ids=${COINGECKO_IDS_CSV}&vs_currencies=usd" 2>/dev/null || echo "{}")
if [ -z "$PRICES_JSON" ] || [ "$PRICES_JSON" = "{}" ]; then
log_error "Failed to fetch prices from CoinGecko"
exit 1
fi
log_success "Prices fetched successfully"
echo ""
# Update each oracle
UPDATED=0
FAILED=0
log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
log_info "Updating Oracle Contracts"
log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
while IFS='|' read -r SYMBOL ADDRESS NAME; do
if [ -z "$SYMBOL" ]; then continue; fi
# Skip if not an oracle/pricefeed token (unless it's a wrapped token that uses ETH oracle)
if [[ ! "$NAME" =~ "Price Feed" ]] && [[ ! "$SYMBOL" =~ ^(WETH|WETH10|ETH)$ ]]; then
continue
fi
COINGECKO_ID="${TOKEN_MAP[$SYMBOL]}"
if [ -z "$COINGECKO_ID" ]; then
log_warn "No CoinGecko mapping for $SYMBOL ($NAME), skipping..."
continue
fi
ORACLE_ADDRESS="${ORACLE_ADDRESSES[$SYMBOL]}"
if [ -z "$ORACLE_ADDRESS" ]; then
log_warn "No oracle address configured for $SYMBOL, skipping..."
continue
fi
# Get price from CoinGecko response
PRICE=$(echo "$PRICES_JSON" | jq -r ".[\"$COINGECKO_ID\"].usd // empty" 2>/dev/null || echo "")
if [ -z "$PRICE" ] || [ "$PRICE" = "null" ] || [ "$PRICE" = "0" ]; then
log_error "Could not get price for $SYMBOL (CoinGecko ID: $COINGECKO_ID)"
((FAILED++))
continue
fi
log_info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
log_info "Updating: $NAME ($SYMBOL)"
log_detail "Oracle Address: $ORACLE_ADDRESS"
log_detail "Current Price: \$$PRICE USD"
# Convert to 8 decimals (oracle format)
PRICE_DECIMALS=$(python3 << PYEOF
price = float("$PRICE")
decimals = int(price * 100000000)
print(decimals)
PYEOF
)
log_detail "Price in 8 decimals: $PRICE_DECIMALS"
# Check 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
CURRENT_ANSWER=$(echo "$CURRENT_ORACLE_DATA" | cut -c 131-194)
CURRENT_PRICE=$(python3 << PYEOF
answer_hex = "$CURRENT_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_detail "Current oracle price: \$$(printf '%.2f' $CURRENT_PRICE)"
# Check if update is needed (only update if difference > 0.5%)
PRICE_DIFF=$(python3 << PYEOF
current = float("$CURRENT_PRICE")
new = float("$PRICE")
if current == 0:
print(100) # Always update if current is zero
else:
diff = abs(new - current) / current * 100
print(diff)
PYEOF
)
if (( $(echo "$PRICE_DIFF < 0.5" | bc -l 2>/dev/null || echo "0") )); then
log_warn "Price difference is less than 0.5% (${PRICE_DIFF}%)"
log_info "Skipping update to save gas"
echo ""
continue
fi
fi
# Update oracle contract
log_info "Sending transaction to update oracle..."
# Try different update methods (use uint256 for updateAnswer)
TX_HASH=""
for METHOD_SIG in "updateAnswer(uint256)" "transmit(int256)" "setLatestAnswer(int256)"; do
METHOD=$(echo "$METHOD_SIG" | cut -d'(' -f1)
TX_HASH=$(cast send "$ORACLE_ADDRESS" \
"$METHOD_SIG" \
"$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', ''))" 2>/dev/null || echo "")
if [ -n "$TX_HASH" ] && [ "$TX_HASH" != "null" ]; then
log_success "Transaction sent using $METHOD: $TX_HASH"
break
fi
done
if [ -z "$TX_HASH" ]; then
log_error "Failed to update oracle for $SYMBOL"
log_warn "Tried methods: updateAnswer, transmit, setLatestAnswer"
((FAILED++))
echo ""
continue
fi
# Wait briefly for confirmation
sleep 3
# Verify 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: \$$(printf '%.2f' $NEW_PRICE) USD"
((UPDATED++))
else
log_warn "Could not verify update (may need more time)"
((UPDATED++))
fi
echo ""
done <<< "$TOKENS"
echo ""
echo "========================================="
echo "Summary"
echo "========================================="
echo ""
log_success "Successfully updated: $UPDATED oracle(s)"
if [ $FAILED -gt 0 ]; then
log_warn "Failed to update: $FAILED oracle(s)"
fi
echo ""
if [ $UPDATED -gt 0 ]; then
log_info "Oracle prices have been updated successfully!"
log_info ""
log_info "Next steps:"
log_info " 1. Verify prices using: cast call <oracle-address> 'latestRoundData()' --rpc-url $RPC_URL"
log_info " 2. Check oracle publisher service is running (VMID 3500) for automatic updates"
log_info " 3. dApps can now query oracle contracts for USD prices"
fi
echo ""