PowerPool
  • powerpool overview
    • PowerPool
      • PowerPool DAO Story
      • Value Proposition
      • Use Cases
      • CVP Token
      • Vision 2027
    • Blockchain Automation
      • Glossary
    • PowerAgent Stats
    • How to contribute
    • Contracts and Links
  • Power Agent
    • đŸŽ¯PowerAgent features
    • đŸ›ī¸Architecture
      • â„šī¸Agent
      • â„šī¸Keeper
      • â„šī¸Job
        • Full Specification
    • 📜User Guides and Instructions
      • ❓I Want to Automate my Tasks
        • Job Registration Guide
      • ❓I Want to Become a Keeper
    • â„šī¸Scenarios
    • ⌛Old Pages
      • Installation Guide (Old)
        • Prerequisites
        • DAppNode Installation
        • Registering in PowerAgent
        • Installing PowerAgent Package on DAppNode
        • Standalone Installation
        • Chain-specific configs
      • Keeper (Old)
        • Keeper Registration and Update
        • Keeper staking, withdrawal, and deactivation
          • Keeper activation and deactivation in PPAgentV2RANDAO
        • Keeper assignment and release in RanDAO realisation
      • Job (Old)
        • Job Registration & Update
        • Job funds deposition and withdrawal
      • Agent (old)
        • Page
        • Execution
      • Technical Implementation (Old)
        • Hooks and helper functions
        • Errors
        • Modifiers
          • Flags
      • Job Registration Guide (Old)
      • 📑Testnet Rules
      • Slashing
        • Copy of Slashing
      • Task Reward and Gas Compensation
        • Fees and income sources
        • Copy of Task Reward and Gas Compensation
  • PowerPool Incentives
    • PowerPool Points Program
  • Security
    • Bug Bounty
    • Security Audits
  • Research
    • Automation Networks Research
      • Approaches on Keeper Selection
      • On-chain Random Number Generation
      • Keeper Weighing
      • 🌊PowerPool & PowerAgent Automation Network
      • Value Proposition-PowerPool
    • PowerAgent v2.1
      • Keeper Selection
      • Hooks
  • Resources
    • Website
    • Twitter
    • Medium
    • Discord
    • Github
    • Telegram
    • Governance Voting
    • Governance Forum
  • Legacy & Deprecated
    • Index Products
      • $YLA: Yearn Lazy Ape
        • Invest (ZAP) in YLA with low fees
        • Instant YLA mint via USDC
        • $CVP Boost Program
        • Redeem YLA
        • YLA Onsen Liquidity Mining [deprecated]
      • $BSCDEFI: BSC DeFi Pool/Index
        • Guide: Mint $BSCDEFI with $BNB
        • Guide: Multi-Asset $BSCDEFI Mint
        • Guide: PancakeSwap LM Farming
        • Add $BSCDEFI to MetaMask.
        • Redeem $BSCDEFI
      • $ASSY: Aave, SushiSwap, Synthetix, and Yearn Index
        • $CVP Boost Program
        • Underlying Token Staking
      • $PIPT: PowerIndex Pool
      • $YETI: Yearn Ecosystem Index
      • Market Price vs Fair Value
      • About ZAP
    • CVP reward program
      • How to create a DCA flow in Partitura
Powered by GitBook
On this page
  • Overview
  • Keeper selection
  • Specification
  • Algorithm
  • Hooks
  • Select a Keeper

Was this helpful?

  1. Power Agent
  2. Old Pages
  3. Agent (old)

Execution

PreviousPageNextTechnical Implementation (Old)

Last updated 1 year ago

Was this helpful?

Overview

The most important part of the PowerAgent operation. This section describes all steps performed by a Keeper and the Agent contract to execute the Job at a given time (or upon satisfying given conditions).

Whenever execution conditions are met, a Keeper is chosen to execute the task. Alternatively, a Keeper can be pre-selected for the next execution when a number of events happen (e.g. the job parameters or credits values change).

Keeper selection

For more information on Keeper selection, see <page>.

⋅⋅⋅\cdot \cdot \cdot⋅⋅⋅

Specification

The chosen Keeper calls the function execute_44g58pv of the Agent contract, passing required dependent on the type of the Job and the config for the execution.

The function is heavily optimized for gas savings; inline assembly is used alongside with binary operations.

cfg

uint256 cfg
0x  |              name               | binary
01  | FLAG_ACCEPT_MAX_BASE_FEE_LIMIT  | 0...001
02  | FLAG_ACCRUE_REWARD              | 0...010

This config is constructed by the Keeper for each execution separately. Setting the flags allows the keeper to override reversion when the block base gas fee exceeds the limit set by the job owner; the second boolean flag determines whether to accrue the reward for the execution on the PowerAgent contract or transfer it to the keeper worker address immediately.

calldata

Algorithm

execute_44g58pv
function execute_44g58pv() external
{
    //Hook called at the very start of the execution.
    _beforeExecution();
    
    //=========Assertions=========
    _assertKeeperHasSufficientStake();
    _assertJobIsActive();
    _assertMinCvpDeposit();
    _assertIntervalHasPassed();
    _assertBaseFee();
    _assertEoaMsgSender();
    
    //=======Calldata load========
    _assertCalldataNotMissing();
    _assertSelectorCheck();
    
    //=========Execution==========
    //Try to execute
    //if execution failed, store Job response in the memory for the purpose of constructing traceback.
    
    //==========Payout==========
    //If execution succeeded, pay compensation + reward
    //Else, pay compensation (in RanDAO; in Flashbots realisation the payment is always in full)
    
    //==========Events============
    //If execution succeeded,
    emit Execute(
        jobKey,
        jobAddress,
        actualKeeperId,
        gasUsed,
        block.basefee,
        tx.gasprice,
        compensation,
        bytes32(binJob)
    );
    //Hook called after successful execution
    _afterExecutionSucceeded(
        jobKey,
        actualKeeperId,
        binJob
    );
    //Else 
    //Hook called after execution reverted
    _afterExecutionReverted(
        jobKey,
        //Type of calldata provided for execution
        calldataSource,
        actualKeeperId,
        //Response from the Job contract stored if the execution reverted
        executionResponse
    );
    
}

Hooks

The hook functions are used to process execution calls by slashers (INSERT LINK TO SLASHING).

Their implementation varies depending on the realisation of the PowerAgent.

_beforeExecute

This hook is called at the very beginning of the execute function. It executes only if the caller is a slasher.

The purpose of this hook is to ensure that by the time the slasher called this function, the slashing has been initiated and the task has been failed by the assigned keeper. If so, after the hook the execution continues, and the slasher becomes the executor of the task. Otherwise, a corresponding error is thrown, and the slasher is reverted.

Flashbots

Not implemented.

RanDAO
function _beforeExecute(
    //jobKey of the job to check
    bytes32 jobKey_,
    
    //id of the keeper which was responsible for execution earlier
    uint256 actualKeeperId_,
    
    //binary of the job
    uint256 binJob_
    ) internal virtual override
    
{
    if (intervalSeconds > 0 && nextKeeperId != actualKeeperId_) {

The hook checks whether the Job is an interval task or a selector task.

  • Interval task

    The assigned keeper can only be slashed if they failed to execute the task during the grace period defined by the rdConfig.period1 parameter, starting from the timestamp at which execution becomes available.

  • Resolver task

    The keeper can be slashed only if the slashing has been initiated (slashing can be initiated by the currently assigned slasher if the job can be executed, i.e., when the designated slasher is capable of executing the job, he may initiate slashing, obtaining the ability to execute the job and slash the designated keeper's stake when the grace period specified by the rdConfig.period1 parameter elapses). Do bear in mind that the only slasher permitted to perform this is the one who initiated slashing.

_afterExecutionSucceeded

Called at the end if the execution was successful.

Flashbots

Not implemented

RanDAO

Handles post-execution slashing when necessary (i.e. when the execution function invoker is a slasher):

function _afterExecutionSucceeded(
    //Key of the executed job
    bytes32 jobKey_,
    
    //ID of the keeper/slasher who successfully executed the task
    uint256 actualKeeperId_,
    
    // Job binary representation
    uint256 binJob_) internal override

The assigned keeper is released, the slashing action parameters set (given the job is of resolver type) are zeroed out, and, if the invoker of the function is not the assigned keeper (i.e. is a slasher), the sum of the static and dynamic slashing fees are subtracted from the CVP stake of the keeper and added to that of the slasher.

_afterExecutionReverted

Called at the end if the transaction was reverted by the Job contract.

Flashbots
function _afterExecutionReverted(
    //reverted job key
    bytes32 jobKey_,
    //job type (SELECTOR, PRE_DEFINED, RESOLVER)
    CalldataSourceType calldataSource_,
    //ID of the keeper whose execution reverted
    uint256 keeperId_,
    //offset pointing to the memory location of the message with which the function reverted
    bytes memory executionResponse_
  ) internal virtual

Handles the returned traceback: if no specifying message is returned, this function reverts with the error revert JobCallRevertedWithoutDetails(), and otherwise it wraps the traceback and compiles a custom message consisting of a pointer to the function revert response and the response itself.

RanDAO
function _afterExecutionReverted(
    //key of the reverted job
    bytes32 jobKey_,
    //type of the reverted job
    CalldataSourceType calldataSource_,
    //ID of the keeper who attempted to execute the job
    uint256 keeperId_,
    //offset pointing to the memory location of the message with which the function reverted
    bytes memory executionResponse_
  )

Unlike in Flashbots, in RanDAO version this hook does not wrap any tracebacks; instead, it reverts with a custom message if a resolver-type function reverted without slashing being initiated, which can happen if the problem is in the job itself (since slashing initiation requires an executability check, and we can assume that a rational slasher initiates slashing immediately after he is able to ascertain possibility of execution) and otherwise emits an event with the execution response pointer passed to the function and releases the keeper assigned.

Select a Keeper

Flashbots

At the current state of PPagentV2, the keeper to execute the task is selected by the Flashbots: the one offering the highest gas price is chosen, others are reverted with no cost.

RanDAO

In the RanDAO version, the choice is made by the following algorithm:

//get the randao realisation for the current block, stored in the block.difficulty
uint256 pseudoRandom = _getPseudoRandom();
//get the cardinality of the keeper set so that the index may be taken modulo it
uint256 totalActiveKeepers = activeKeepers.length();
//get the minimal CVP stake demanded of the keeper by the job
uint256 _jobMinKeeperCvp = jobMinKeeperCvp[jobKey_];
//obtain the index by taking the pseudorandom input, adding the job key so that variance in chosen keeper indices is observed within any single block, and mapping the result into the keeper index set by taking the modulo operation
//the resultant variable index is the index of the keeper selected for execution
uint256 index;
unchecked {
      index = ((pseudoRandom + uint256(jobKey_)) % totalActiveKeepers);
    }
//iterate over all the keepers, starting with the randomly selected one, until a keeper admissible for the job at hand is found or all gas has been expended
while (true) {
      //effectively modulo operation
      if (index  >= totalActiveKeepers) {
        index = 0;
      }
      //obtain the ID of the next keeper by the index selected
      uint256 _nextExecutionKeeperId = activeKeepers.at(index);
      //required stake is set to be the global minimal demanded CVP unless the job has a specification of its own
      uint256 requiredStake = _jobMinKeeperCvp > 0 ? _jobMinKeeperCvp : minKeeperCvp;
      //load the keeper object at the selected ID
      Keeper memory keeper = keepers[_nextExecutionKeeperId];
      //if the keeper is admissible, i.e. active and has sufficient stake, then assign him as the next keeper of the job and terminate the passage
      if (keeper.isActive && keeper.cvpStake >= requiredStake) {
        jobNextKeeperId[jobKey_] = _nextExecutionKeeperId;
        
        keeperLocksByJob[_nextExecutionKeeperId].add(jobKey_);
        emit KeeperJobLock(_nextExecutionKeeperId, jobKey_);
        return;
      }
      index += 1;
      }
  }

Keeper assignment only takes place at either a corresponding external call by a job owner, after a successful job execution, after a job is registered; if a job changes its activity status or credit amount deposited, the keeper is assigned conditionally if the job has at least the minimal admissible amount of credits (specified by the RanDAO realisation config parameter rdConfig.jobMinCreditsFinney).

Calldata passed by the keeper for the target function execution. Read for information on execution calldata.

Choosing a keeper by random seems like a .

⌛
smart idea
Drawing
calldata
this section