The Keeper is the one who initiates execution of a task.
Overview
The keeper is a combination of two blockchain addresses and an off-chain bot. The purpose of the bot is to watch all jobs available in the PowerAgent and offer its candidature for task execution as soon as the conditions for the execution are met.
Keeper is an externally owned account linked to an abstract Keeper object by a key-Worker (abstract object used in PowerAgent to represent keepers) relation; groups of Workers also may share Admins. The purpose of the keeper to invoke Agent's function execute_44g58pv when conditions are met.
Addresses
A keeper needs two addresses: Admin address for management and Worker address for execution.
Admin - this address is used for management of CVP stake and registration and configuration of Worker addresses.
Worker - is registered as the keeper address in the Agent contract. On behalf of this address the tasks are executed. The rewards may be configured to be paid immediately to this address or be collected on the Agent contract and thereafter withdrawn, refer to <section>.
Bot
The bot connects to the blockchain via a websocket RPC connection and continuously listens to events from the blockchain. When the conditions for the execution are met, the bot sends the transaction from the Worker address to the Agent contract. It is recommended to set up a private node to maintain the quality of connection on one's own.
â â â
Specification
This section describes the on-chain part of the Keeper only. For off-chain software, refer to the <section>.
Structure
The Keeper is represented in the Agent as the following structure Keeper:
Keeper structure
structKeeper {//address of the keeperaddress worker;//keeperâs stake in CVPuint88 cvpStake;//indicator of the keeper being active (i.e. able to execute jobs)bool isActive;}
Mappings
All mappings related to the Keeper structure in the Agent:
Keeper mappings list
//Internally tracked ID (enumeration of keepers)mapping(uint256=> Keeper) keepers;//Keeperâs admin, which is defined as an address that is permitted to authorise changes to this keepermapping(uint256=>address) keeperAdmins;//The totality of the CVP amount for which a keeperâs stake is slashedmapping(uint256=>uint256) slashedStakeOf;//The compensation in native chain tokens a keeper has accruedmapping(uint256=>uint256) compensations;//The amount of CVP for which the redemption process has started and is currently pendingmapping(uint256=>uint256) pendingWithdrawalAmounts;//The timestamp at which the time-out ends, allowing the keeper or the admin thereof to call finalizeRedeem and withdraw the pending amount.
mapping(uint256=>uint256) pendingWithdrawalEndsAt;//Reverse mapping of keepers, defining an isomorphism between keeper addresses and IDs. mapping(address=>uint256) workerKeeperIds;
RanDAO-specific mappings
// Gives a set of pending (locking in a certain sense) jobs for a keepermapping(uint256=> EnumerableSet.Bytes32Set) internal keeperLocksByJob;// Gives timestamp at which keeper activation (staggered in time in RanDAO realisation) can be finalisedmapping(uint256=>uint256) public keeperActivationCanBeFinalizedAt;
Functions
The list of functions used to manage and update Keeper information:
registerAsKeeper
Registers a new keeper and stores the information in the corresponding mappings.
functionregisterAsKeeper (//keeper worker addressaddress worker_,//initial CVP stake deposit amountuint256 initialDepositAmount_//returns id of the newly registered keeper ) publicvirtualreturns (uint256 keeperId){//asserts the provided address is not already a worker_assertWorkerNotAssigned()//asserts the provided CVP meets the minimal amount requirementminKeeperCvp_assertion() ...}
setWorkerAddress
Updates a keeperâs worker address. Should be called from keeper admin address.
functionsetWorkerAddress (//id of the keeper which worker address should be changeduint256 keeperId_,//a new address for the workeraddress worker_ ) external{//Only Admin address is allowed to change the worker address_assertOnlyKeeperAdmin()//Assert that this address is not already registered as a worker_assertWorkerNotAssigned() ...}
withdrawCompensation
Immediately withdraws the keeperâs compensation in native tokens.
functinon withdrawCompensation() (//id of the keeper to withdraw compensation foruint256 keeperId_,//address to which to withdraw the compensationaddresspayable to_,//the amount to withdrawuint256 amount_ ) external{//Assert that there is something to withdraw_assertNonZeroAmount()//Only keeper admin and worker addresses are allowed to withdraw compensation_assertOnlyKeeperAdminOrWorker()//Can't withdraw more compensation than is availableamount_not_exceeds_available_assertion() ...}
stake
Deposits CVP to a given keeperâs stake.
functionstake (//id of the keeper to stake CVP foruint256 keeperId_,//amount of CVP to stakeuint256 amount_ ) external{//Assert that the amount provided is not zero_assertNonZeroAmount()//Assert that there is a keeper assigned to this id_assertKeeperIdExists()//Assert that the final amount after stake doesn't overflow max amount (uint88)no_amount_after_overflow_assertion() ...}
initiateRedeem
Prepares CVP for withdrawal by first burning staked tokens to compensate the slashed amount (if any) and then accumulating the remainder as amount pending for withdrawal. The cooldown period, specified by the agent config, is re-initiated after every call of the function, even if the pending value before the call was nonzero.
functioninitiateRedeem (//id of the keeper to reedem fromuint256 keeperId_,//amount of CVP to redeemuint256 amount_,//Returns the timestamp when the redeem can be finalized ) externalreturns (uint256 pendingWithdrawalAfter){//Only keeper admin _assertOnlyKeeperAdmin()//Can't redeem nothing_assertNonZeroAmount()//Hook before the Redeem, specifiable by particular realisations_beforeInitiateRedeem()//Can't redeem more than is stakedamount_not_exceeds_stake_assertion() //If the keeper undergoes slashing, can't withdraw the part that is reserved for slashing until all slashed amount is compensated
amount_sufficient_to_compensate_slashed_stake_assertion() ...}
finalizeRedeem
Finalizes CVP withdrawal and sends the previously staked tokens to a specified address.
functionfinalizeRedeem (//id of the keeper to finalize redeem foruint256 keeperId_//address to transfer the redeemed CVP toaddress to_//Returns the amount of CVP redeemed in case of success ) externalreturns (uint256 redeemedCvp){//Assert that the withdrawal cooldown period has passedwithdrawal_time_limit_elapsed_assertion()//Assert that withdrawal of a nonzero amount is actually pendingpending_withdrawal_extant() ...}
Job lock-related RanDAO-specific functions
releaseJob
Manually releases a keeper from executing a job.
functionreleaseJob(//key of the job to releasebytes32 jobKey_) external {//only Admin can release_assertOnlyKeeperAdmin(assignedKeeperId);// Release if insufficient creditsif (_releaseKeeperIfRequired(jobKey_, assignedKeeperId)) {return; }// 2. Check interval timeouts otherwise// 2.1 If interval jobuint256 period2EndsAt = lastExecutionAt + rdConfig.period1 + rdConfig.period2;if (period2EndsAt > block.timestamp) {revertTooEarlyToRelease(jobKey_, period2EndsAt); } // else can release// 2.2 If resolver job// if slashing process initiatedif (_jobSlashingPossibleAfter !=0) {//admissibility period end timestampuint256 period2EndsAt = _jobSlashingPossibleAfter + rdConfig.period2;//can't release if locked by initiated slashingif (period2EndsAt > block.timestamp) {revertTooEarlyToRelease(jobKey_, period2EndsAt); }// if no slashing initiated } else {revertCantRelease(); }}_releaseKeeper(jobKey_, assignedKeeperId);}