The PPAgentV2 (later The Agent) contract stores the state of the PowerAgent network. It includes the list of keepers, the logic of task execution, and keeper management. PPAgentV2 is an upgradeable descendant, direct or indirect, of PPAgentV2.sol.
The Agent is responsible for the following operations:
Keeper Registration
To participate in the PowerAgent network, a keeper has to register in the system by calling the registerAsKeeper function and provide at least minimal CVP stake.
Job Registration
The contract to be automated must be registered in The Agent. For this, the owner of the contract provides the address of the contract, and the configuration of the job, including the type, and tops up the job balance for keepers' reward.
Transaction xecution
To execute the task (once the conditions for execution are met), the keeper calls execute the Agent contract function. After a series of check-ups, the call is passed by The Agent to the Job contract and the task is executed, or in case of any errors, the execution will revert with a corresponding error.
Job Update
Job owners can update the Job configuration at any time, for example, change the function of the contract to be executed, or update the conditions by which the contract should be executed. Each time a change is made, a Job with new id is created and attached to the same Job contract.
Slashing
The PowerAgent has the algorithm of punishment for malicious or negligent keepers. Various tasks can have different cost of no execution, and expensive tasks require stable and reliable execution. To prevent keepers from misbehavior, the slashing system is implemented in The Agent. If the execution of a task is failed (or not performed in time), the keeper is slashed for a certain portion of their CVP stake. This portion depends on the task specific minimal CVP stake and the cost of no execution.
Keeper Removal
Once a keeper wishes to quit participation in the PowerAgent network, they call the function initiateRedeem. A process of stake release is launched. After a cooldown period that is specified by the job parameters, the keeper can withdraw their CVP stake by invoking finalizeRedeem.
â â â
Specification
Internal constants
The Agent possesses the following internal (i.e., accessible to inheritors) constants:
//Capping of the maximum possible delay in fund withdrawaluint256 MAX_PENDING_WITHDRAWAL_TIMEOUT_SECONDS =30days; //2_592_000 sec//Capping the maximum fee in parts per million an Agent can setuint256 MAX_FEE_PPM =5e4;//Multiplier for fixed (i.e. static) rewardsuint256 FIXED_PAYMENT_MULTIPLIER =1e15;
Values of any inheritor Agent instance may not exceed the cap imposed by the corresponding internal parameter constant.
Internal variables
The Agent possesses the following internal (i.e., accessible to inheritors) variables:
//Minimal acceptable CVP value for the keeper stake to haveuint256 minKeeperCvp;//Minimal time interval between redeem initialization and redeem finalizationuint256 pendingWithdrawalTimeoutSeconds;//The totality of fees the Agent has accrued thus faruint256 feeTotal;//Fee retained by the Agent for its services in parts per million uint256 feePpm;//The index of last keeper (having the meaning of the keeper pool size)uint256 lastKeeperId;
rdConfig
RanDAO realisation also possesses a configuration Struct rdConfig, constructed to be exactly 24 bytes in size.
structRandaoConfig {// max: 2^8 - 1 = 255 blocks//the size of slashing epoch in blocks; may not be less than 3uint8 slashingEpochBlocks;// max: 2^24 - 1 = 16777215 seconds ~ 194 days//the size of the grace period during which execution is possible, but the keeper is not slashable//no less than 15 secondsuint24 period1;// max: 2^16 - 1 = 65535 seconds ~ 18 hours//the size of the admissibility period, during which slashing is possible and cannot be re-initiated (i.e. execution is overdue, but the job does not yet have an overdue status). In addition, a job cannot be released by a keeper until overdue (this restriction does not apply to release by owner). //no less than 15 secondsuint16 period2;// in 1 CVP. max: 16_777_215 CVP. The value here is multiplied by 1e18 in calculations.//Fixed part of the slashing fee; no greater than half of the minimal Agent-wide admissible stakeuint24 slashingFeeFixedCVP;// In BPS; 1 basis point = 0.01%//governs the dynamic part of the slashing fee; no greater than 50% (5000 bps)uint16 slashingFeeBps;// max: 2^16 - 1 = 65535, in calculations is multiplied by 0.001 ether (1 finney),// thus the min is 0.001 ether and max is 65.535 ether//minimal amount of credits a job must possess to be assigned and retain keepers for execution; expressed in finneys (1 F = 1e-3 ETH)uint16 jobMinCreditsFinney;// max 2^40 ~= 1.1e12, in calculations is multiplied by 1 ether// Agent-wide upper cap on the stake of a keeper for the purposes of computing compensation; set at zero to disable Agent-wide capping considerations (job-wide capping may stil be carried out in such a case)//!!!WE MUST ASK KOLYAN WHETHER IT IS PLANNED TO CAP JOB WIDE MAX STAKE AT AGENT WIDE MAX STAKE; AS OF NOW, JOB WIDE MAX STAKE IS IMPOSSIBLE TO SET IN ANY WAY - ISSUE RESOLVED; job wide max stake is the fixedReward field in the binary representation. DELETE this comment when acknowledged !!!uint40 agentMaxCvpStake;// max: 2^16 - 1 = 65535, where 10_000 is 100%// determines the size of the dynamic part of the compensation in basis points of total gas expenditure uint16 jobCompensationMultiplierBps;// max: 2^32 - 1 = 4_294_967_295// determines the constant scaling factor of the (possible capped) keeper stake which yields the fixed part of the rewarduint32 stakeDivisor;// max: 2^8 - 1 = 255 hours, or ~10.5 days// determines the time delay between keeper activation being initiated and finaliseduint8 keeperActivationTimeoutHours; }
Functions
Initialization
The Agent instance is initialized by an eponymous function initialize which accepts the following arguments:
functioninitialize(//Agentâs owner addressaddress owner;//Minimal acceptable CVP value for the keeper stake to haveuint256 minKeeperCvp_;//Minimal time interval between redeem initialization and redeem finalization uint256 pendingWithdrawalTimeoutSeconds_; )
This function sets the Agentâs configuration parameters and ownership to those specified.
RanDAO
In the RanDAO realisation, agent instantiation accepts additional arguments that are required for this implementation to work
functioninitializeRandao(//Agent owner's addressaddress owner_,//Minimal stake accepted for a keeper by the Agentuint256 minKeeperCvp_,//Minimal time interval between redeem initialization and redeem finalizationuint256 pendingWithdrawalTimeoutSeconds_,//rdConfig parametersRandaoConfigmemory rdConfig_)
A detailed description of RandaoConfig is available at rdConfig.
Parameter update
Function setAgentParams updates the configuration of the Agent. Appropriate parameters are capped by the corresponding internal constants.
functionsetAgentParams(//Minimal acceptable CVP for the keeper to stakeuint256 minKeeperCvp_,//The time a stake withdrawal must spend in a pending stateuint256 timeoutSeconds_,//Fee retained by the Agent in parts per millionuint256 feePpm_ )
RanDAO
In RanDAO, additional parameters are extant, calling for an extra parameter-setting function (setAgentParams is not virtual).
Since some of the capping constants are not defined in code, we supply the entire annotated checklist.
//make sure the slashing epoch is not too short; this is not a vitally necessary restriction, but it is useful, since it somewhat mitigates the effects of the grace period being no less than 15 seconds, giving keepers more time to execute slashing of interval jobs if (rdConfig_.slashingEpochBlocks <3) {revertSlashingEpochBlocksTooLow();}//make sure the grace period is at least 15 seconds. Utility is quite self-explanatory, since it would be a bad move to permit slashing of keepers e.g. immediately when job execution is possible.if (rdConfig_.period1 <15seconds) {revertInvalidPeriod1();}//make sure the admissibility period is at least 15 seconds. Also self-explanatory; equivalent to period1, but for slashers. if (rdConfig_.period2 <15seconds) {revertInvalidPeriod2();}//make sure the fixed slashing fee is no greater than half of the minimum Agent-permitted stake. The one-half value is due to simultaneous dynamic slashing fee bps restriction. if (rdConfig_.slashingFeeFixedCVP > (minKeeperCvp /2)) {revertInvalidSlashingFeeFixedCVP();}//make sure the dynamic slashing fee is no greater than 5000 bps/50%. Ensures that the slashed stake during any one slashing event is capped by 100% of the keeper's stake. if (rdConfig_.slashingFeeBps >5000) {revertSlashingBpsGt5000Bps();}//make sure the inverse of the coefficient for the fixed (gas-independent) part of keeper reward is not zeroif (rdConfig_.stakeDivisor ==0) {revertInvalidStakeDivisor();}
Fee withdrawal
The function withdrawFees withdraws all fees the Agent has accrued to a specified address.
functionwithdrawFees(//where to withdraw; needs to be payable to invoke transferaddress payable to_) external {//only Agent owner can call_assertOnlyOwner();//current accrued feesuint256 amount = feeTotal;//we withdraw all fees feeTotal =0;//and transfer them to the specfieid address to_.transfer(amount);emitWithdrawFees(to_, amount); }
Custom structures
The Agent contract contains custom data structures storing information about Keepers and Jobs.