- 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.
297 lines
10 KiB
Bash
Executable File
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 ""
|
|
|