# Automated Price Feed Keeper Setup Guide **Date**: 2025-01-27 **Status**: ✅ **COMPLETE** --- ## Overview This guide explains how to set up automated price feed updates using the PriceFeedKeeper contract. The keeper automatically updates price feeds at regular intervals, ensuring prices stay current. --- ## Architecture ### Components 1. **PriceFeedKeeper Contract** - On-chain keeper contract 2. **Keeper Service** - Off-chain service that calls the keeper 3. **OraclePriceFeed** - Price feed oracle integration ### Flow ``` Keeper Service (Off-chain) │ ▼ PriceFeedKeeper Contract │ ▼ OraclePriceFeed │ ▼ ReserveSystem ``` --- ## Deployment ### Step 1: Deploy PriceFeedKeeper ```bash # Set environment variables export PRIVATE_KEY= export RPC_URL_138= export ORACLE_PRICE_FEED= export RESERVE_ADMIN= # Optional: Asset addresses to track export XAU_ASSET= export USDC_ASSET= export ETH_ASSET= # Optional: Keeper address (defaults to deployer) export KEEPER_ADDRESS= # Deploy keeper forge script script/reserve/DeployKeeper.s.sol:DeployKeeper \ --rpc-url chain138 \ --broadcast \ --verify ``` ### Step 2: Track Assets Assets must be tracked before the keeper can update them: ```solidity // Via contract call keeper.trackAsset(xauAsset); keeper.trackAsset(usdcAsset); keeper.trackAsset(ethAsset); ``` Or use the deployment script which automatically tracks assets if provided. --- ## Keeper Service Options ### Option 1: Node.js Keeper Service (Recommended) **Requirements**: - Node.js 16+ - npm packages: `ethers`, `dotenv` **Setup**: ```bash # Install dependencies npm install ethers dotenv # Set environment variables export RPC_URL_138= export KEEPER_PRIVATE_KEY= export PRICE_FEED_KEEPER_ADDRESS= export UPDATE_INTERVAL=30 # seconds # Run keeper service node scripts/reserve/keeper-service.js ``` **Features**: - Automatic retry logic - Error handling - Statistics tracking - Graceful shutdown - Event parsing ### Option 2: Bash Keeper Service **Setup**: ```bash # Set environment variables export RPC_URL_138= export PRICE_FEED_KEEPER_ADDRESS= export UPDATE_INTERVAL=30 # seconds # Make script executable chmod +x scripts/reserve/keeper-service.sh # Run keeper service ./scripts/reserve/keeper-service.sh ``` **Features**: - Simple bash implementation - Uses Foundry scripts - Basic error handling ### Option 3: Chainlink Keepers **Setup**: 1. Register keeper contract with Chainlink Keepers 2. Fund keeper with LINK tokens 3. Configure upkeep interval **Configuration**: ```javascript // Register upkeep const keeperRegistry = await ethers.getContractAt("KeeperRegistry", registryAddress); await keeperRegistry.registerUpkeep( keeperAddress, // Keeper contract address gasLimit, // Gas limit for upkeep adminAddress, // Admin address checkData, // Check data (empty for our keeper) amount, // LINK amount to fund source, // Source address encryptedEmail // Encrypted email (optional) ); ``` ### Option 4: Gelato Network **Setup**: 1. Register task with Gelato 2. Configure execution interval 3. Fund with native token **Configuration**: ```javascript // Register task const gelato = await ethers.getContractAt("Gelato", gelatoAddress); await gelato.createTask( keeperAddress, // Task contract "performUpkeep()", // Function selector interval, // Execution interval executor // Executor address ); ``` --- ## Manual Upkeep ### Check if Upkeep is Needed ```bash forge script script/reserve/CheckUpkeep.s.sol:CheckUpkeep \ --rpc-url chain138 ``` ### Perform Upkeep ```bash export KEEPER_PRIVATE_KEY= export PRICE_FEED_KEEPER_ADDRESS= forge script script/reserve/PerformUpkeep.s.sol:PerformUpkeep \ --rpc-url chain138 \ --broadcast ``` --- ## Configuration ### Update Interval Set the update interval (in seconds): ```solidity keeper.setUpdateInterval(60); // 60 seconds ``` ### Maximum Updates Per Call Limit the number of assets updated per call: ```solidity keeper.setMaxUpdatesPerCall(20); // Update up to 20 assets per call ``` ### Track/Untrack Assets ```solidity // Track asset keeper.trackAsset(assetAddress); // Untrack asset keeper.untrackAsset(assetAddress); ``` --- ## Monitoring ### Check Keeper Status ```solidity // Get tracked assets address[] memory assets = keeper.getTrackedAssets(); // Check if asset needs update bool needsUpdate = keeper.needsUpdate(assetAddress); // Get update interval uint256 interval = keeper.updateInterval(); ``` ### Monitor Events Listen for `PriceFeedsUpdated` events: ```javascript keeper.on("PriceFeedsUpdated", (assets, timestamp, event) => { console.log("Updated assets:", assets); console.log("Timestamp:", timestamp); }); ``` --- ## Running as a Service ### Systemd Service Create `/etc/systemd/system/price-feed-keeper.service`: ```ini [Unit] Description=Price Feed Keeper Service After=network.target [Service] Type=simple User=keeper WorkingDirectory=/path/to/smom-dbis-138 Environment="RPC_URL_138=https://rpc.d-bis.org" Environment="KEEPER_PRIVATE_KEY=0x..." Environment="PRICE_FEED_KEEPER_ADDRESS=0x..." Environment="UPDATE_INTERVAL=30" ExecStart=/usr/bin/node scripts/reserve/keeper-service.js Restart=always RestartSec=10 [Install] WantedBy=multi-user.target ``` **Enable and start**: ```bash sudo systemctl enable price-feed-keeper sudo systemctl start price-feed-keeper sudo systemctl status price-feed-keeper ``` ### Docker Service Create `docker-compose.yml`: ```yaml version: '3.8' services: keeper: image: node:18 working_dir: /app volumes: - .:/app environment: - RPC_URL_138=${RPC_URL_138} - KEEPER_PRIVATE_KEY=${KEEPER_PRIVATE_KEY} - PRICE_FEED_KEEPER_ADDRESS=${PRICE_FEED_KEEPER_ADDRESS} - UPDATE_INTERVAL=30 command: node scripts/reserve/keeper-service.js restart: unless-stopped ``` **Run**: ```bash docker-compose up -d docker-compose logs -f keeper ``` --- ## Troubleshooting ### Keeper Not Updating **Check**: 1. Keeper has `KEEPER_ROLE` 2. Assets are tracked 3. Update interval has passed 4. Keeper service is running **Solution**: ```bash # Check upkeep status forge script script/reserve/CheckUpkeep.s.sol:CheckUpkeep --rpc-url chain138 # Manually perform upkeep forge script script/reserve/PerformUpkeep.s.sol:PerformUpkeep --rpc-url chain138 --broadcast ``` ### Gas Estimation Errors **Error**: `Gas estimation failed` **Solution**: 1. Check keeper has sufficient balance 2. Verify assets are tracked 3. Check update interval hasn't passed 4. Verify oracle price feed is configured ### Transaction Failures **Error**: `Transaction reverted` **Solution**: 1. Check keeper role permissions 2. Verify oracle price feed address 3. Check asset aggregators are set 4. Verify price feeds are not stale --- ## Security Considerations 1. **Private Key Security**: Store keeper private key securely 2. **Access Control**: Use multi-sig for admin functions 3. **Rate Limiting**: Set appropriate update intervals 4. **Monitoring**: Monitor keeper transactions and failures 5. **Backup**: Run multiple keeper instances for redundancy --- ## Best Practices 1. **Multiple Keepers**: Run multiple keeper instances for redundancy 2. **Monitoring**: Set up alerts for keeper failures 3. **Gas Management**: Monitor gas prices and adjust intervals 4. **Error Handling**: Implement retry logic and error reporting 5. **Logging**: Log all keeper activities for auditing --- ## Cost Estimation ### Gas Costs - **Check Upkeep**: ~30,000 gas (view function, no cost) - **Perform Upkeep**: ~100,000 - 300,000 gas per asset - **Update 10 Assets**: ~1,000,000 - 3,000,000 gas ### Frequency - **Update Interval**: 30 seconds (recommended) - **Updates Per Day**: 2,880 - **Gas Per Day**: ~2.88M - 8.64M gas (for 10 assets) ### Cost (at 20 gwei) - **Per Update**: 0.02 - 0.06 ETH - **Per Day**: 57.6 - 172.8 ETH - **Per Month**: 1,728 - 5,184 ETH **Note**: Costs vary based on gas prices and number of assets. --- ## References - [Price Feed Setup](./PRICE_FEED_SETUP.md) - [Reserve System Integration](./INTEGRATION_COMPLETE.md) - [Chainlink Keepers](https://docs.chain.link/chainlink-automation) - [Gelato Network](https://docs.gelato.network)