Deployment & Keeper Bot Guide
This technical guide provides instructions for deploying the QanVault smart contracts and running the automated keeper bots that coordinate draws and rollovers.
What is a Keeper Bot and Why Does It Exist?#
A fundamental reality of Ethereum and BNB Smart Chain is that smart contracts cannot execute on their own clock. Unlike traditional web applications with background cron daemons, a smart contract is a passive state machine that only runs when an external transaction is submitted to the network.
To resolve draws at exactly 00:00:00 UTC, verify commit-reveal randomness, and trigger 72-hour prize rollovers without centralized human intervention, decentralized protocols rely on Keepers:
- Stateless Automation: A keeper bot is simply a lightweight script that monitors block timestamps and calls public transition methods (e.g.
commitDraw,revealDraw, andtriggerRollover). - Permissionless & Verifiable: Any community member or node runner can run this script using public RPC endpoints.
- Decentralization Proof: Publishing this guide in the technical whitepaper proves that QanVault does not depend on private admin keys or black-box servers to operate its prize cycles.
Toolchain & Dependencies#
- Language: Solidity
0.8.24 - Development Framework: Hardhat
- Libraries: OpenZeppelin Contracts v5, Ethers v6, Viem
- TypeScript: v5.4+
- Node.js: v18.17+ or v20+
Contract Deployment Workflow#
1. Configure Environment Variables
Create a .env file in the project root:
BSC_RPC_URL="https://bsc-dataseed.binance.org/"
ETH_RPC_URL="https://eth.llamarpc.com"
DEPLOYER_PRIVATE_KEY="0x..."
BSCSCAN_API_KEY="..."
ETHERSCAN_API_KEY="..."2. Compile Contracts
Compile with Hardhat using viaIR optimization:
npx hardhat compile3. Deploy to BNB Smart Chain
Run the deployment script for the canonical settlement hub:
npx hardhat run scripts/deploy-bsc-hub.ts --network bscThis script:
- Deploys
PrizeEscrowVaultwith the initial 5-bucket configuration. - Deploys
EverpotCorelinked to the vault. - Sets
EverpotCoreas the exclusive authorized drawer onPrizeEscrowVault. - Deploys
MultiChainRouterconfigured with PancakeSwap v3 router parameters.
Keeper Bot Architecture#
Keepers are stateless, automated worker scripts that interact with the contracts to advance the draw state machine.
1. Daily Draw Keeper
Runs once every 24 hours at 00:00:00 UTC:
import { ethers } from "ethers";
async function executeDailyDraw(coreContract: ethers.Contract, keeperSigner: ethers.Signer) {
const drawId = await coreContract.getCurrentDrawId();
// Step 1: Generate secret entropy & commitment
const secretSeed = ethers.hexlify(ethers.randomBytes(32));
const currentBlock = await keeperSigner.provider!.getBlockNumber();
const commitment = ethers.keccak256(
ethers.concat([secretSeed, ethers.toBeHex(drawId, 32), ethers.toBeHex(currentBlock, 32)])
);
// Step 2: Submit hash commitment
const commitTx = await coreContract.connect(keeperSigner).commitDraw(drawId, commitment);
await commitTx.wait(2);
// Step 3: Reveal seed & finalize draw
const revealTx = await coreContract.connect(keeperSigner).revealDraw(drawId, secretSeed);
await revealTx.wait(1);
console.log(`Draw #${drawId} successfully finalized!`);
}2. Hourly Rollover Keeper
Runs every 60 minutes to detect and process expired claim windows:
async function processExpiredRollovers(coreContract: ethers.Contract, keeperSigner: ethers.Signer) {
const expiredDraws = await coreContract.getUnclaimedExpiredDraws();
for (const drawId of expiredDraws) {
console.log(`Triggering rollover for draw #${drawId}...`);
const tx = await coreContract.connect(keeperSigner).triggerRollover(drawId);
await tx.wait(1);
console.log(`Draw #${drawId} rolled over into subsequent pot.`);
}
}Next Steps#
- Security guarantees and test verification: Security Audit & Invariants
- Complete FAQ: General FAQ