#!/bin/bash # Complete Keeper Deployment Script # Deploys all keeper components and sets up monitoring set -e # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' CYAN='\033[0;36m' NC='\033[0m' DRY_RUN="${DRY_RUN:-0}" EXPECTED_KEEPER="0xD3AD6831aacB5386B8A25BB8D8176a6C8a026f04" for arg in "$@"; do case "$arg" in --dry-run) DRY_RUN=1 ;; esac done # Load environment variables if [ -f .env ]; then # shellcheck disable=SC1091 source .env fi # Configuration RPC_URL="${RPC_URL_138:-https://rpc.d-bis.org}" PRIVATE_KEY="${PRIVATE_KEY}" KEEPER_ADDRESS="${PRICE_FEED_KEEPER_ADDRESS}" normalize_addr() { echo "$1" | tr '[:upper:]' '[:lower:]' } validate_keeper_env() { if [ -z "$KEEPER_ADDRESS" ]; then echo -e "${RED}ERROR: PRICE_FEED_KEEPER_ADDRESS is not set in .env${NC}" echo -e "${YELLOW}Expected: PRICE_FEED_KEEPER_ADDRESS=${EXPECTED_KEEPER}${NC}" exit 1 fi if [ "$(normalize_addr "$KEEPER_ADDRESS")" != "$(normalize_addr "$EXPECTED_KEEPER")" ]; then echo -e "${RED}ERROR: PRICE_FEED_KEEPER_ADDRESS mismatch${NC}" echo -e " .env: ${KEEPER_ADDRESS}" echo -e " expected: ${EXPECTED_KEEPER}" exit 1 fi } dry_run_msg() { echo -e "${CYAN}[DRY RUN]${NC} $*" } run_forge_broadcast() { local script_path="$1" forge script "$script_path" \ --rpc-url "$RPC_URL" \ --broadcast \ --verify } print_forge_would_run() { local label="$1" local script_path="$2" dry_run_msg "$label" echo " forge script $script_path --rpc-url \"$RPC_URL\" --broadcast --verify" } if [ "$DRY_RUN" = "1" ]; then echo -e "${CYAN}=== Complete Keeper Deployment (DRY RUN) ===${NC}\n" validate_keeper_env echo -e "${GREEN}PRICE_FEED_KEEPER_ADDRESS (.env):${NC} $KEEPER_ADDRESS" echo -e "${GREEN}RPC_URL:${NC} $RPC_URL" echo "" echo -e "${YELLOW}Step 1: PriceFeedKeeper${NC}" dry_run_msg "Skip deploy; keeper already configured at $KEEPER_ADDRESS" echo "" if [ "$DEPLOY_CHAINLINK" = "true" ]; then echo -e "${YELLOW}Step 2: ChainlinkKeeperCompatible (DEPLOY_CHAINLINK=true)${NC}" print_forge_would_run "Would deploy ChainlinkKeeperCompatible" \ "script/reserve/DeployChainlinkKeeper.s.sol:DeployChainlinkKeeper" dry_run_msg "Would append CHAINLINK_KEEPER_COMPATIBLE_ADDRESS to .env (skipped)" dry_run_msg "Follow-up: node scripts/reserve/chainlink-keeper-setup.js" echo "" else echo -e "${YELLOW}Step 2: ChainlinkKeeperCompatible${NC}" dry_run_msg "Skipped (set DEPLOY_CHAINLINK=true to include)" echo "" fi if [ "$DEPLOY_GELATO" = "true" ]; then echo -e "${YELLOW}Step 3: GelatoKeeperCompatible (DEPLOY_GELATO=true)${NC}" print_forge_would_run "Would deploy GelatoKeeperCompatible" \ "script/reserve/DeployGelatoKeeper.s.sol:DeployGelatoKeeper" dry_run_msg "Would append GELATO_KEEPER_COMPATIBLE_ADDRESS to .env (skipped)" dry_run_msg "Follow-up: node scripts/reserve/gelato-keeper-setup.js" echo "" else echo -e "${YELLOW}Step 3: GelatoKeeperCompatible${NC}" dry_run_msg "Skipped (set DEPLOY_GELATO=true to include)" echo "" fi echo -e "${YELLOW}Step 4: Verify deployment${NC}" dry_run_msg "Would run read-only upkeep check (no --broadcast):" echo " forge script script/reserve/CheckUpkeep.s.sol:CheckUpkeep --rpc-url \"$RPC_URL\"" echo "" echo -e "${GREEN}=== Dry Run Complete (no transactions broadcast, .env unchanged) ===${NC}" exit 0 fi echo -e "${GREEN}=== Complete Keeper Deployment ===${NC}\n" # Step 1: Deploy PriceFeedKeepe echo -e "${YELLOW}Step 1: Deploying PriceFeedKeeper...${NC}" if [ -z "$KEEPER_ADDRESS" ]; then run_forge_broadcast "script/reserve/DeployKeeper.s.sol:DeployKeeper" # Extract keeper address from output KEEPER_ADDRESS=$(forge script script/reserve/DeployKeeper.s.sol:DeployKeeper \ --rpc-url "$RPC_URL" 2>&1 | grep "PriceFeedKeeper deployed at:" | awk '{print $NF}') echo "export PRICE_FEED_KEEPER_ADDRESS=$KEEPER_ADDRESS" >> .env echo -e "${GREEN}✓ PriceFeedKeeper deployed: $KEEPER_ADDRESS${NC}\n" else echo -e "${GREEN}✓ PriceFeedKeeper already deployed: $KEEPER_ADDRESS${NC}\n" fi # Step 2: Deploy Chainlink Keeper Compatible (optional) if [ "$DEPLOY_CHAINLINK" = "true" ]; then echo -e "${YELLOW}Step 2: Deploying ChainlinkKeeperCompatible...${NC}" run_forge_broadcast "script/reserve/DeployChainlinkKeeper.s.sol:DeployChainlinkKeeper" CHAINLINK_KEEPER=$(forge script script/reserve/DeployChainlinkKeeper.s.sol:DeployChainlinkKeeper \ --rpc-url "$RPC_URL" 2>&1 | grep "ChainlinkKeeperCompatible deployed at:" | awk '{print $NF}') echo "export CHAINLINK_KEEPER_COMPATIBLE_ADDRESS=$CHAINLINK_KEEPER" >> .env echo -e "${GREEN}✓ ChainlinkKeeperCompatible deployed: $CHAINLINK_KEEPER${NC}\n" echo -e "${YELLOW}Next: Register with Chainlink Keepers:${NC}" echo "node scripts/reserve/chainlink-keeper-setup.js" echo "" fi # Step 3: Deploy Gelato Keeper Compatible (optional) if [ "$DEPLOY_GELATO" = "true" ]; then echo -e "${YELLOW}Step 3: Deploying GelatoKeeperCompatible...${NC}" run_forge_broadcast "script/reserve/DeployGelatoKeeper.s.sol:DeployGelatoKeeper" GELATO_KEEPER=$(forge script script/reserve/DeployGelatoKeeper.s.sol:DeployGelatoKeeper \ --rpc-url "$RPC_URL" 2>&1 | grep "GelatoKeeperCompatible deployed at:" | awk '{print $NF}') echo "export GELATO_KEEPER_COMPATIBLE_ADDRESS=$GELATO_KEEPER" >> .env echo -e "${GREEN}✓ GelatoKeeperCompatible deployed: $GELATO_KEEPER${NC}\n" echo -e "${YELLOW}Next: Create task with Gelato:${NC}" echo "node scripts/reserve/gelato-keeper-setup.js" echo "" fi # Step 4: Verify deployment echo -e "${YELLOW}Step 4: Verifying deployment...${NC}" forge script script/reserve/CheckUpkeep.s.sol:CheckUpkeep \ --rpc-url "$RPC_URL" echo -e "\n${GREEN}=== Deployment Complete ===${NC}" echo "" echo "Keeper Address: $KEEPER_ADDRESS" echo "" echo -e "${YELLOW}Next Steps:${NC}" echo "1. Start keeper service:" echo " node scripts/reserve/keeper-service.js" echo "" echo "2. Start monitor service:" echo " node scripts/reserve/monitor-keeper.js" echo "" echo "3. Or use Docker:" echo " docker-compose -f docker/docker-compose.keeper.yml up -d" echo "" echo "4. Or use systemd:" echo " sudo systemctl enable price-feed-keeper" echo " sudo systemctl start price-feed-keeper"