Files
smom-dbis-138/scripts/deployment/deploy-all.sh
defiQUG 1fb7266469 Add Oracle Aggregator and CCIP Integration
- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control.
- Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities.
- Created .gitmodules to include OpenZeppelin contracts as a submodule.
- Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment.
- Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks.
- Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring.
- Created scripts for resource import and usage validation across non-US regions.
- Added tests for CCIP error handling and integration to ensure robust functionality.
- Included various new files and directories for the orchestration portal and deployment scripts.
2025-12-12 14:57:48 -08:00

548 lines
19 KiB
Bash
Executable File

#!/usr/bin/env bash
# Deploy All - Complete deployment automation for ChainID 138
# This script automates the entire deployment process including infrastructure, contracts, and MetaMask integration
set -euo pipefail
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../lib/init.sh"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
DEPLOYMENT_LOG="${PROJECT_ROOT}/deployment.log"
CONTRACT_ADDRESSES_FILE="${PROJECT_ROOT}/contracts-deployed.json"
# Load environment variables
if [ -f "${PROJECT_ROOT}/.env" ]; then
set -a
source "${PROJECT_ROOT}/.env"
set +a
else
log_error "Error: .env file not found. Please create .env file from .env.example"
exit 1
fi
# Logging function
log() {
log_success "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$DEPLOYMENT_LOG"
}
error() {
log_error "[ERROR] $1" | tee -a "$DEPLOYMENT_LOG"
exit 1
}
warn() {
log_warn "[WARNING] $1" | tee -a "$DEPLOYMENT_LOG"
}
# Check Azure authentication
check_azure_auth() {
log "Checking Azure authentication..."
# Check if Azure CLI is installed
if ! command -v az &> /dev/null; then
error "Azure CLI is not installed. Please install it first: https://docs.microsoft.com/cli/azure/install-azure-cli"
fi
# Check if user is logged in
if ! az account show &> /dev/null; then
error "Azure CLI is not authenticated. Please run 'az login' first."
error "
error "For WSL users:"
error " 1. Run 'az login' in WSL"
error " 2. Or use service principal: az login --service-principal -u <app-id> -p <password> --tenant <tenant-id>"
error " 3. Or use managed identity if running on Azure VM"
error "
error "After logging in, verify with: az account show"
exit 1
fi
# Get current subscription
local current_sub=$(az account show --query id -o tsv 2>/dev/null || echo "")
if [ -z "$current_sub" ]; then
error "Failed to get current Azure subscription"
exit 1
fi
# Check if subscription matches (if AZURE_SUBSCRIPTION_ID is set)
if [ -n "${AZURE_SUBSCRIPTION_ID:-}" ] && [ "$current_sub" != "$AZURE_SUBSCRIPTION_ID" ]; then
warn "Current Azure subscription ($current_sub) does not match AZURE_SUBSCRIPTION_ID ($AZURE_SUBSCRIPTION_ID)"
warn "Setting subscription to: $AZURE_SUBSCRIPTION_ID"
az account set --subscription "$AZURE_SUBSCRIPTION_ID" || error "Failed to set Azure subscription"
fi
log "Azure authentication verified"
log "Current subscription: $current_sub"
}
# Check prerequisites
check_prerequisites() {
log "Checking prerequisites..."
local missing=0
# Check required tools
for cmd in az terraform kubectl helm forge cast jq; do
if ! command -v "$cmd" &> /dev/null; then
error "$cmd is not installed"
missing=1
fi
done
# Check Azure authentication (if Azure-related tasks are not skipped)
if [ "$SKIP_INFRASTRUCTURE" != "true" ] || [ "$SKIP_KUBERNETES" != "true" ] || [ "$SKIP_CLOUDFLARE" != "true" ]; then
check_azure_auth
fi
# Check environment variables (conditional based on what's being deployed)
local required_vars=()
if [ "$SKIP_INFRASTRUCTURE" != "true" ] || [ "$SKIP_KUBERNETES" != "true" ] || [ "$SKIP_CLOUDFLARE" != "true" ]; then
required_vars+=("AZURE_SUBSCRIPTION_ID" "AZURE_RESOURCE_GROUP")
fi
if [ "$SKIP_CLOUDFLARE" != "true" ]; then
required_vars+=("CLOUDFLARE_API_TOKEN" "CLOUDFLARE_ZONE_ID")
fi
if [ "$SKIP_CONTRACTS" != "true" ]; then
required_vars+=("RPC_URL" "PRIVATE_KEY")
fi
for var in "${required_vars[@]}"; do
if [ -z "${!var:-}" ]; then
error "Required environment variable $var is not set"
fi
done
if [ $missing -eq 0 ]; then
log "All prerequisites met"
fi
}
# Deploy Azure Infrastructure
deploy_infrastructure() {
log "Deploying Azure infrastructure..."
cd "${PROJECT_ROOT}/terraform" || error "Failed to change directory to terraform"
# Initialize Terraform
if [ ! -d ".terraform" ]; then
log "Initializing Terraform..."
terraform init -upgrade || error "Terraform initialization failed"
fi
# Plan deployment
log "Planning Terraform deployment..."
terraform plan -out=tfplan || error "Terraform plan failed"
# Apply deployment
log "Applying Terraform deployment..."
terraform apply tfplan || error "Terraform apply failed"
# Get outputs (if they exist)
log "Getting Terraform outputs..."
AKS_NAME=$(terraform output -raw aks_name 2>/dev/null || echo "")
AKS_RG=$(terraform output -raw aks_resource_group 2>/dev/null || echo "$AZURE_RESOURCE_GROUP")
# Configure kubectl (if AKS name is available)
if [ -n "$AKS_NAME" ]; then
log "Configuring kubectl..."
az aks get-credentials --resource-group "$AKS_RG" --name "$AKS_NAME" --overwrite-existing || error "Failed to get AKS credentials"
else
warn "AKS name not found in Terraform outputs, skipping kubectl configuration"
fi
log "Infrastructure deployment completed"
}
# Deploy Kubernetes Resources
deploy_kubernetes() {
log "Deploying Kubernetes resources..."
# Create namespace
kubectl create namespace besu-network --dry-run=client -o yaml | kubectl apply -f - || warn "Namespace may already exist"
# Deploy validators
log "Deploying validators..."
helm upgrade --install besu-validators "${PROJECT_ROOT}/helm/besu-network" \
-f "${PROJECT_ROOT}/helm/besu-network/values-validators.yaml" \
-n besu-network \
--wait --timeout=10m || error "Failed to deploy validators"
# Deploy sentries
log "Deploying sentries..."
helm upgrade --install besu-sentries "${PROJECT_ROOT}/helm/besu-network" \
-f "${PROJECT_ROOT}/helm/besu-network/values-sentries.yaml" \
-n besu-network \
--wait --timeout=10m || error "Failed to deploy sentries"
# Deploy RPC nodes
log "Deploying RPC nodes..."
helm upgrade --install besu-rpc "${PROJECT_ROOT}/helm/besu-network" \
-f "${PROJECT_ROOT}/helm/besu-network/values-rpc.yaml" \
-n besu-network \
--wait --timeout=10m || error "Failed to deploy RPC nodes"
# Wait for RPC nodes to be ready
log "Waiting for RPC nodes to be ready..."
kubectl wait --for=condition=ready pod -l component=rpc -n besu-network --timeout=300s || error "RPC nodes not ready"
log "Kubernetes deployment completed"
}
# Deploy Blockscout
deploy_blockscout() {
log "Deploying Blockscout..."
# Deploy Blockscout database
kubectl apply -f "${PROJECT_ROOT}/k8s/blockscout/deployment.yaml" || error "Failed to deploy Blockscout"
# Wait for database to be ready
log "Waiting for Blockscout database to be ready..."
kubectl wait --for=condition=ready pod -l app=blockscout-db -n besu-network --timeout=300s || error "Blockscout database not ready"
# Wait for Blockscout to be ready
log "Waiting for Blockscout to be ready..."
kubectl wait --for=condition=ready pod -l app=blockscout -n besu-network --timeout=600s || error "Blockscout not ready"
log "Blockscout deployment completed"
}
# Deploy Contracts
deploy_contracts() {
log "Deploying contracts..."
cd "${PROJECT_ROOT}" || error "Failed to change directory to project root"
# Initialize contract addresses file
echo "{}" > "$CONTRACT_ADDRESSES_FILE"
# Deploy WETH
log "Deploying WETH..."
WETH_ADDRESS=$(forge script script/DeployWETH.s.sol \
--rpc-url "$RPC_URL" \
--broadcast \
--private-key "$PRIVATE_KEY" \
-vvv 2>&1 | grep -oP 'Contract deployed at: \K0x[a-fA-F0-9]{40}' || echo "")
if [ -z "$WETH_ADDRESS" ]; then
error "Failed to deploy WETH"
fi
log "WETH deployed at: $WETH_ADDRESS"
jq ".weth = \"$WETH_ADDRESS\"" "$CONTRACT_ADDRESSES_FILE" > "${CONTRACT_ADDRESSES_FILE}.tmp" && mv "${CONTRACT_ADDRESSES_FILE}.tmp" "$CONTRACT_ADDRESSES_FILE"
# Deploy Multicall individually (if not using Deploy.s.sol)
if [ -z "$MULTICALL_ADDRESS" ] || [ "$MULTICALL_ADDRESS" = "null" ]; then
log "Deploying Multicall..."
DEPLOY_OUTPUT=$(forge script script/DeployMulticall.s.sol \
--rpc-url "$RPC_URL" \
--broadcast \
--private-key "$PRIVATE_KEY" \
-vvv 2>&1 | tee "${PROJECT_ROOT}/deploy-multicall.log" || echo "")
MULTICALL_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oP 'Contract deployed at: \K0x[a-fA-F0-9]{40}' || \
echo "$DEPLOY_OUTPUT" | grep -oP 'Deployed to: \K0x[a-fA-F0-9]{40}' || \
jq -r '.transactions[0].contractAddress // empty' "${PROJECT_ROOT}/broadcast/DeployMulticall.s.sol/138/run-latest.json" 2>/dev/null || echo "")
if [ -z "$MULTICALL_ADDRESS" ] || [ "$MULTICALL_ADDRESS" = "null" ]; then
error "Failed to deploy Multicall. Check deployment logs: ${PROJECT_ROOT}/deploy-multicall.log"
fi
fi
log "Multicall deployed at: $MULTICALL_ADDRESS"
jq ".multicall = \"$MULTICALL_ADDRESS\"" "$CONTRACT_ADDRESSES_FILE" > "${CONTRACT_ADDRESSES_FILE}.tmp" && mv "${CONTRACT_ADDRESSES_FILE}.tmp" "$CONTRACT_ADDRESSES_FILE"
# Deploy Oracle Aggregator individually (if not using Deploy.s.sol)
if [ -z "$ORACLE_ADDRESS" ] || [ "$ORACLE_ADDRESS" = "null" ]; then
log "Deploying Oracle Aggregator..."
DEPLOY_OUTPUT=$(forge script script/DeployOracle.s.sol \
--rpc-url "$RPC_URL" \
--broadcast \
--private-key "$PRIVATE_KEY" \
-vvv 2>&1 | tee "${PROJECT_ROOT}/deploy-oracle.log" || echo "")
ORACLE_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oP 'Contract deployed at: \K0x[a-fA-F0-9]{40}' || \
echo "$DEPLOY_OUTPUT" | grep -oP 'Deployed to: \K0x[a-fA-F0-9]{40}' || \
jq -r '.transactions[0].contractAddress // empty' "${PROJECT_ROOT}/broadcast/DeployOracle.s.sol/138/run-latest.json" 2>/dev/null || echo "")
if [ -z "$ORACLE_ADDRESS" ] || [ "$ORACLE_ADDRESS" = "null" ]; then
error "Failed to deploy Oracle Aggregator. Check deployment logs: ${PROJECT_ROOT}/deploy-oracle.log"
fi
fi
log "Oracle Aggregator deployed at: $ORACLE_ADDRESS"
jq ".oracle = \"$ORACLE_ADDRESS\"" "$CONTRACT_ADDRESSES_FILE" > "${CONTRACT_ADDRESSES_FILE}.tmp" && mv "${CONTRACT_ADDRESSES_FILE}.tmp" "$CONTRACT_ADDRESSES_FILE"
# Save all addresses
if [ -n "$WETH_ADDRESS" ] && [ "$WETH_ADDRESS" != "null" ]; then
jq ".weth = \"$WETH_ADDRESS\"" "$CONTRACT_ADDRESSES_FILE" > "${CONTRACT_ADDRESSES_FILE}.tmp" && mv "${CONTRACT_ADDRESSES_FILE}.tmp" "$CONTRACT_ADDRESSES_FILE"
fi
if [ -n "$MULTICALL_ADDRESS" ] && [ "$MULTICALL_ADDRESS" != "null" ]; then
jq ".multicall = \"$MULTICALL_ADDRESS\"" "$CONTRACT_ADDRESSES_FILE" > "${CONTRACT_ADDRESSES_FILE}.tmp" && mv "${CONTRACT_ADDRESSES_FILE}.tmp" "$CONTRACT_ADDRESSES_FILE"
fi
if [ -n "$ORACLE_ADDRESS" ] && [ "$ORACLE_ADDRESS" != "null" ]; then
jq ".oracle = \"$ORACLE_ADDRESS\"" "$CONTRACT_ADDRESSES_FILE" > "${CONTRACT_ADDRESSES_FILE}.tmp" && mv "${CONTRACT_ADDRESSES_FILE}.tmp" "$CONTRACT_ADDRESSES_FILE"
fi
# Deploy CCIP Router (optional)
if [ -f "${PROJECT_ROOT}/script/DeployCCIPRouter.s.sol" ]; then
log "Deploying CCIP Router..."
DEPLOY_OUTPUT=$(forge script script/DeployCCIPRouter.s.sol \
--rpc-url "$RPC_URL" \
--broadcast \
--private-key "$PRIVATE_KEY" \
-vvv 2>&1 | tee "${PROJECT_ROOT}/deploy-ccip.log" || echo "")
CCIP_ROUTER_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oP 'Contract deployed at: \K0x[a-fA-F0-9]{40}' || \
echo "$DEPLOY_OUTPUT" | grep -oP 'Deployed to: \K0x[a-fA-F0-9]{40}' || \
jq -r '.transactions[0].contractAddress // empty' "${PROJECT_ROOT}/broadcast/DeployCCIPRouter.s.sol/138/run-latest.json" 2>/dev/null || echo "")
if [ -n "$CCIP_ROUTER_ADDRESS" ] && [ "$CCIP_ROUTER_ADDRESS" != "null" ]; then
log "CCIP Router deployed at: $CCIP_ROUTER_ADDRESS"
jq ".ccipRouter = \"$CCIP_ROUTER_ADDRESS\"" "$CONTRACT_ADDRESSES_FILE" > "${CONTRACT_ADDRESSES_FILE}.tmp" && mv "${CONTRACT_ADDRESSES_FILE}.tmp" "$CONTRACT_ADDRESSES_FILE"
else
warn "CCIP Router deployment failed (may be optional)"
fi
else
warn "CCIP Router deployment script not found, skipping"
fi
log "Contract deployment completed"
log "Contract addresses saved to: $CONTRACT_ADDRESSES_FILE"
}
# Update Token List
update_token_list() {
log "Updating token list with deployed addresses..."
if [ ! -f "$CONTRACT_ADDRESSES_FILE" ]; then
error "Contract addresses file not found: $CONTRACT_ADDRESSES_FILE"
fi
WETH_ADDRESS=$(jq -r '.weth' "$CONTRACT_ADDRESSES_FILE")
if [ -z "$WETH_ADDRESS" ] || [ "$WETH_ADDRESS" = "null" ]; then
error "WETH address not found in contract addresses file"
fi
# Update token-list.json
log "Updating token-list.json with WETH address: $WETH_ADDRESS"
jq ".tokens[0].address = \"$WETH_ADDRESS\"" "${PROJECT_ROOT}/metamask/token-list.json" > "${PROJECT_ROOT}/metamask/token-list.json.tmp" && \
mv "${PROJECT_ROOT}/metamask/token-list.json.tmp" "${PROJECT_ROOT}/metamask/token-list.json"
log "Token list updated"
}
# Configure Cloudflare DNS
configure_cloudflare_dns() {
log "Configuring Cloudflare DNS..."
# Get Application Gateway IP
cd "${PROJECT_ROOT}/terraform" || error "Failed to change directory to terraform"
APP_GATEWAY_NAME=$(terraform output -raw app_gateway_name 2>/dev/null || echo "")
if [ -z "$APP_GATEWAY_NAME" ]; then
error "Application Gateway name not found in Terraform outputs"
fi
APP_GATEWAY_IP=$(az network application-gateway show \
--resource-group "$AZURE_RESOURCE_GROUP" \
--name "$APP_GATEWAY_NAME" \
--query "frontendIPConfigurations[0].publicIpAddress.id" \
-o tsv 2>/dev/null | xargs az network public-ip show --ids --query ipAddress -o tsv 2>/dev/null || echo "")
if [ -z "$APP_GATEWAY_IP" ]; then
error "Failed to get Application Gateway IP. Please provide IP address manually or check Application Gateway configuration."
fi
log "Application Gateway IP: $APP_GATEWAY_IP"
cd "${PROJECT_ROOT}" || error "Failed to change directory to project root"
# Create DNS records
"${PROJECT_ROOT}/scripts/deployment/cloudflare-dns.sh" \
--zone-id "$CLOUDFLARE_ZONE_ID" \
--api-token "$CLOUDFLARE_API_TOKEN" \
--ip "$APP_GATEWAY_IP" || error "Failed to configure Cloudflare DNS"
log "Cloudflare DNS configured"
}
# Verify Deployment
verify_deployment() {
log "Verifying deployment..."
# Check RPC endpoint
log "Checking RPC endpoint..."
if curl -s -X POST "$RPC_URL" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
| jq -e '.result' > /dev/null; then
log "RPC endpoint is accessible"
else
error "RPC endpoint is not accessible"
fi
# Check Blockscout
EXPLORER_URL="${EXPLORER_URL:-https://explorer.d-bis.org}"
log "Checking Blockscout explorer..."
if curl -s -f "$EXPLORER_URL" > /dev/null; then
log "Blockscout explorer is accessible"
else
warn "Blockscout explorer is not accessible (may take time to start)"
fi
# Check contracts
log "Checking deployed contracts..."
if [ -f "$CONTRACT_ADDRESSES_FILE" ]; then
WETH_ADDRESS=$(jq -r '.weth' "$CONTRACT_ADDRESSES_FILE")
if [ -n "$WETH_ADDRESS" ] && [ "$WETH_ADDRESS" != "null" ]; then
# Verify contract code
CODE=$(cast code "$WETH_ADDRESS" --rpc-url "$RPC_URL" || echo "0x")
if [ "$CODE" != "0x" ]; then
log "WETH contract verified at: $WETH_ADDRESS"
else
warn "WETH contract code not found (may need to wait for block confirmation)"
fi
fi
fi
log "Deployment verification completed"
}
# Parse command line arguments
parse_args() {
SKIP_INFRASTRUCTURE=false
SKIP_KUBERNETES=false
SKIP_BLOCKSCOUT=false
SKIP_CONTRACTS=false
SKIP_CLOUDFLARE=false
SKIP_TOKEN_LIST=false
while [[ $# -gt 0 ]]; do
case $1 in
--skip-infrastructure)
SKIP_INFRASTRUCTURE=true
shift
;;
--skip-kubernetes)
SKIP_KUBERNETES=true
shift
;;
--skip-blockscout)
SKIP_BLOCKSCOUT=true
shift
;;
--skip-contracts)
SKIP_CONTRACTS=true
shift
;;
--skip-cloudflare)
SKIP_CLOUDFLARE=true
shift
;;
--skip-token-list)
SKIP_TOKEN_LIST=true
shift
;;
--help)
echo "Usage: $0 [options]"
echo "Options:"
echo " --skip-infrastructure Skip infrastructure deployment"
echo " --skip-kubernetes Skip Kubernetes deployment"
echo " --skip-blockscout Skip Blockscout deployment"
echo " --skip-contracts Skip contract deployment"
echo " --skip-cloudflare Skip Cloudflare DNS configuration"
echo " --skip-token-list Skip token list update"
echo " --help Show this help message"
exit 0
;;
*)
error "Unknown option: $1. Use --help for usage information."
;;
esac
done
}
# Main deployment function
main() {
log "Starting complete deployment process..."
log "Deployment log: $DEPLOYMENT_LOG"
# Parse command line arguments
parse_args "$@"
# Step 0: Check Azure authentication (if needed)
if [ "$SKIP_INFRASTRUCTURE" != "true" ] || [ "$SKIP_KUBERNETES" != "true" ] || [ "$SKIP_CLOUDFLARE" != "true" ]; then
log "Azure authentication is required for this deployment"
log "If not already logged in, run: ./scripts/deployment/azure-login.sh"
log "Or for WSL users: az login"
fi
# Step 1: Check prerequisites
check_prerequisites
# Step 2: Deploy infrastructure
if [ "$SKIP_INFRASTRUCTURE" != "true" ]; then
deploy_infrastructure
else
log "Skipping infrastructure deployment"
fi
# Step 3: Deploy Kubernetes resources
if [ "$SKIP_KUBERNETES" != "true" ]; then
deploy_kubernetes
else
log "Skipping Kubernetes deployment"
fi
# Step 4: Deploy Blockscout
if [ "$SKIP_BLOCKSCOUT" != "true" ]; then
deploy_blockscout
else
log "Skipping Blockscout deployment"
fi
# Step 5: Configure Cloudflare DNS
if [ "$SKIP_CLOUDFLARE" != "true" ]; then
configure_cloudflare_dns
else
log "Skipping Cloudflare DNS configuration"
fi
# Step 6: Deploy contracts
if [ "$SKIP_CONTRACTS" != "true" ]; then
deploy_contracts
else
log "Skipping contract deployment"
fi
# Step 7: Update token list
if [ "$SKIP_TOKEN_LIST" != "true" ] && [ "$SKIP_CONTRACTS" != "true" ]; then
update_token_list
else
log "Skipping token list update"
fi
# Step 8: Verify deployment
verify_deployment
log "Deployment completed successfully!"
log "Contract addresses: $CONTRACT_ADDRESSES_FILE"
log "Next steps:"
log " 1. Verify contracts on Blockscout: $EXPLORER_URL"
log " 2. Update token-list.json with deployed addresses"
log " 3. Submit Ethereum-Lists PR: ./scripts/deployment/submit-ethereum-lists-pr.sh"
log " 4. Submit token list: ./scripts/deployment/submit-token-list.sh"
}
# Run main function
main "$@"