ETH Price: $3,273.69 (-10.99%)

Contract

0x000000000000774D54F4064ec64bEaAdeF498Ae8
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Finalize Redeem190775382024-01-24 15:58:11330 days ago1706111891IN
0x00000000...deF498Ae8
0 ETH0.0007755415.42082966
Finalize Redeem190775342024-01-24 15:57:23330 days ago1706111843IN
0x00000000...deF498Ae8
0 ETH0.0007913215.73454662
Finalize Redeem190775302024-01-24 15:56:35330 days ago1706111795IN
0x00000000...deF498Ae8
0 ETH0.001095416.25419552
Initiate Redeem190336552024-01-18 12:09:47336 days ago1705579787IN
0x00000000...deF498Ae8
0 ETH0.0028366835.27288625
Initiate Redeem190336512024-01-18 12:08:59336 days ago1705579739IN
0x00000000...deF498Ae8
0 ETH0.0027753534.51028597
Initiate Redeem190336462024-01-18 12:07:59336 days ago1705579679IN
0x00000000...deF498Ae8
0 ETH0.0028346735.2478917
Finalize Redeem173364902023-05-25 13:35:23574 days ago1685021723IN
0x00000000...deF498Ae8
0 ETH0.0028726342.61820421
Initiate Redeem173359962023-05-25 11:55:11574 days ago1685015711IN
0x00000000...deF498Ae8
0 ETH0.0025576831.80371968
Finalize Redeem173208602023-05-23 8:50:11577 days ago1684831811IN
0x00000000...deF498Ae8
0 ETH0.002034340.44021448
Initiate Redeem169057032023-03-25 16:36:11635 days ago1679762171IN
0x00000000...deF498Ae8
0 ETH0.0016115220.03855756
Finalize Redeem169034442023-03-25 8:59:23636 days ago1679734763IN
0x00000000...deF498Ae8
0 ETH0.0010730415.91954576
Finalize Redeem169033582023-03-25 8:42:11636 days ago1679733731IN
0x00000000...deF498Ae8
0 ETH0.0008733817.36205777
Initiate Redeem169033522023-03-25 8:40:59636 days ago1679733659IN
0x00000000...deF498Ae8
0 ETH0.0013447216.72101219
Finalize Redeem169033452023-03-25 8:39:35636 days ago1679733575IN
0x00000000...deF498Ae8
0 ETH0.0008191916.28494232
Initiate Redeem169033382023-03-25 8:38:11636 days ago1679733491IN
0x00000000...deF498Ae8
0 ETH0.0015768919.6080167
Finalize Redeem169033312023-03-25 8:36:47636 days ago1679733407IN
0x00000000...deF498Ae8
0 ETH0.0008800417.49460251
Initiate Redeem169033222023-03-25 8:34:59636 days ago1679733299IN
0x00000000...deF498Ae8
0 ETH0.0013437316.70873778
Finalize Redeem168992212023-03-24 18:44:11636 days ago1679683451IN
0x00000000...deF498Ae8
0 ETH0.0016876325.03764974
Finalize Redeem168992142023-03-24 18:42:47636 days ago1679683367IN
0x00000000...deF498Ae8
0 ETH0.0017068425.32254522
Initiate Redeem168992092023-03-24 18:41:47636 days ago1679683307IN
0x00000000...deF498Ae8
0 ETH0.00193124.01115649
Initiate Redeem168992052023-03-24 18:40:59636 days ago1679683259IN
0x00000000...deF498Ae8
0 ETH0.0019042423.6784538
Finalize Redeem168991782023-03-24 18:35:35636 days ago1679682935IN
0x00000000...deF498Ae8
0 ETH0.0016916525.09723
Initiate Redeem168991662023-03-24 18:33:11636 days ago1679682791IN
0x00000000...deF498Ae8
0 ETH0.0019375924.09316737
Finalize Redeem168983542023-03-24 15:49:23636 days ago1679672963IN
0x00000000...deF498Ae8
0 ETH0.0010051338
Initiate Redeem168983502023-03-24 15:48:35636 days ago1679672915IN
0x00000000...deF498Ae8
0 ETH0.0032168440
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
168931312023-03-23 22:13:11637 days ago1679609591
0x00000000...deF498Ae8
0.36661322 ETH
168931292023-03-23 22:12:47637 days ago1679609567
0x00000000...deF498Ae8
0.28922363 ETH
168931242023-03-23 22:11:47637 days ago1679609507
0x00000000...deF498Ae8
0.4656187 ETH
168926452023-03-23 20:34:47637 days ago1679603687
0x00000000...deF498Ae8
0.00221891 ETH
168924642023-03-23 19:58:23637 days ago1679601503
0x00000000...deF498Ae8
0.00216753 ETH
168920432023-03-23 18:33:47637 days ago1679596427
0x00000000...deF498Ae8
0.00249617 ETH
168913522023-03-23 16:14:35637 days ago1679588075
0x00000000...deF498Ae8
0.00261596 ETH
168907602023-03-23 14:14:11637 days ago1679580851
0x00000000...deF498Ae8
0.00183257 ETH
168907582023-03-23 14:13:47637 days ago1679580827
0x00000000...deF498Ae8
0.00177321 ETH
168854892023-03-22 20:24:59638 days ago1679516699
0x00000000...deF498Ae8
0.00260496 ETH
168852052023-03-22 19:27:59638 days ago1679513279
0x00000000...deF498Ae8
0.00211302 ETH
168848902023-03-22 18:23:59638 days ago1679509439
0x00000000...deF498Ae8
0.00187005 ETH
168842982023-03-22 16:24:47638 days ago1679502287
0x00000000...deF498Ae8
0.00175117 ETH
168842902023-03-22 16:22:59638 days ago1679502179
0x00000000...deF498Ae8
0.00173573 ETH
168836952023-03-22 14:22:35638 days ago1679494955
0x00000000...deF498Ae8
0.00174237 ETH
168834072023-03-22 13:23:59638 days ago1679491439
0x00000000...deF498Ae8
0.00145473 ETH
168831032023-03-22 12:22:23638 days ago1679487743
0x00000000...deF498Ae8
0.00128158 ETH
168825102023-03-22 10:22:11638 days ago1679480531
0x00000000...deF498Ae8
0.00100842 ETH
168825092023-03-22 10:21:59638 days ago1679480519
0x00000000...deF498Ae8
0.00094115 ETH
168796702023-03-22 0:49:35639 days ago1679446175
0x00000000...deF498Ae8
0.00099986 ETH
168793842023-03-21 23:51:11639 days ago1679442671
0x00000000...deF498Ae8
0.00094843 ETH
168787872023-03-21 21:50:35639 days ago1679435435
0x00000000...deF498Ae8
0.00103316 ETH
168787792023-03-21 21:48:59639 days ago1679435339
0x00000000...deF498Ae8
0.00113939 ETH
168781892023-03-21 19:49:59639 days ago1679428199
0x00000000...deF498Ae8
0.00134562 ETH
168778862023-03-21 18:48:35639 days ago1679424515
0x00000000...deF498Ae8
0.00151095 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PPAgentV2

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200000 runs

Other Settings:
default evmVersion
File 1 of 5 : PPAgentV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./PPAgentV2Flags.sol";

library ConfigFlags {
  function check(uint256 cfg, uint256 flag) internal pure returns (bool) {
    return (cfg & flag) != 0;
  }
}

interface IPPAgentV2Executor {
  function execute_44g58pv() external;
}

interface IPPAgentV2Viewer {
  struct Job {
    uint8 config;
    bytes4 selector;
    uint88 credits;
    uint16 maxBaseFeeGwei;
    uint16 rewardPct;
    uint32 fixedReward;
    uint8 calldataSource;

    // For interval jobs
    uint24 intervalSeconds;
    uint32 lastExecutionAt;
  }

  struct Resolver {
    address resolverAddress;
    bytes resolverCalldata;
  }

  function getConfig() external view returns (
    uint256 minKeeperCvp_,
    uint256 pendingWithdrawalTimeoutSeconds_,
    uint256 feeTotal_,
    uint256 feePpm_,
    uint256 lastKeeperId_
  );
  function getKeeper(uint256 keeperId_) external view returns (
    address admin,
    address worker,
    uint256 currentStake,
    uint256 slashedStake,
    uint256 compensation,
    uint256 pendingWithdrawalAmount,
    uint256 pendingWithdrawalEndAt
  );
  function getKeeperWorkerAndStake(uint256 keeperId_) external view returns (
    address worker,
    uint256 currentStake
  );
  function getJob(bytes32 jobKey_) external view returns (
    address owner,
    address pendingTransfer,
    uint256 jobLevelMinKeeperCvp,
    Job memory details,
    bytes memory preDefinedCalldata,
    Resolver memory resolver
  );
  function getJobRaw(bytes32 jobKey_) external view returns (uint256 rawJob);
  function jobOwnerCredits(address owner_) external view returns (uint256 credits);
}

/**
 * @title PowerAgentLite
 * @author PowerPool
 */
contract PPAgentV2 is IPPAgentV2Executor, IPPAgentV2Viewer, PPAgentV2Flags, Ownable {
  error OnlyOwner();
  error NonEOASender();
  error InsufficientKeeperStake();
  error InsufficientJobScopedKeeperStake();
  error KeeperWorkerNotAuthorized();
  error InsufficientJobCredits(uint256 actual, uint256 wanted);
  error InsufficientJobOwnerCredits(uint256 actual, uint256 wanted);
  error InactiveJob(bytes32 jobKey);
  error JobIdOverflow();
  error OnlyJobOwner();
  error JobWithoutOwner();
  error MissingJobAddress();
  error MissingMaxBaseFeeGwei();
  error NoFixedNorPremiumPctReward();
  error CreditsDepositOverflow();
  error CreditsWithdrawalUnderflow();
  error MissingDeposit();
  error IntervalNotReached(uint256 lastExecutedAt, uint256 interval, uint256 _now);
  error BaseFeeGtGasPrice(uint256 baseFee, uint256 jobMaxBaseFeeGwei);
  error InvalidCalldataSource();
  error MissingInputCalldata();
  error SelectorCheckFailed();
  error JobCallRevertedWithoutDetails();
  error InsufficientAmountToCoverSlashedStake(uint256 wanted, uint256 actual);
  error AmountGtStake(uint256 wanted, uint256 actualStake, uint256 actualSlashedStake);
  error WithdrawalTimoutNotReached();
  error NoPendingWithdrawal();
  error MissingAmount();
  error WithdrawAmountExceedsAvailable(uint256 wanted, uint256 actual);
  error JobShouldHaveInterval();
  error InvalidJobAddress();
  error MissingResolverAddress();
  error NotSupportedByJobCalldataSource();
  error OnlyKeeperAdmin();
  error OnlyKeeperAdminOrWorker();
  error TimeoutTooBig();
  error FeeTooBig();
  error InsufficientAmount();
  error OnlyPendingOwner();
  error WorkerAlreadyAssigned();

  string public constant VERSION = "2.2.0";
  uint256 internal constant MAX_PENDING_WITHDRAWAL_TIMEOUT_SECONDS = 30 days;
  uint256 internal constant MAX_FEE_PPM = 5e4;
  uint256 internal constant FIXED_PAYMENT_MULTIPLIER = 1e15;
  uint256 internal constant JOB_RUN_GAS_OVERHEAD = 40_000;

  enum CalldataSourceType {
    SELECTOR,
    PRE_DEFINED,
    RESOLVER
  }

  IERC20 public immutable CVP;

  event Execute(
    bytes32 indexed jobKey,
    address indexed job,
    uint256 keeperId,
    uint256 gasUsed,
    uint256 baseFee,
    uint256 gasPrice,
    uint256 compensation,
    bytes32 binJobAfter
  );
  event WithdrawFees(address indexed to, uint256 amount);
  event Slash(uint256 indexed keeperId, address indexed to, uint256 currentAmount, uint256 pendingAmount);
  event RegisterAsKeeper(uint256 indexed keeperId, address indexed keeperAdmin, address indexed keeperWorker);
  event SetWorkerAddress(uint256 indexed keeperId, address indexed prev, address indexed worker);
  event Stake(uint256 indexed keeperId, uint256 amount, address staker);
  event InitiateRedeem(uint256 indexed keeperId, uint256 redeemAmount, uint256 stakeAmount, uint256 slashedStakeAmount);
  event FinalizeRedeem(uint256 indexed keeperId, address indexed beneficiary, uint256 amount);
  event WithdrawCompensation(uint256 indexed keeperId, address indexed to, uint256 amount);
  event DepositJobCredits(bytes32 indexed jobKey, address indexed depositor, uint256 amount, uint256 fee);
  event WithdrawJobCredits(bytes32 indexed jobKey, address indexed owner, address indexed to, uint256 amount);
  event DepositJobOwnerCredits(address indexed jobOwner, address indexed depositor, uint256 amount, uint256 fee);
  event WithdrawJobOwnerCredits(address indexed jobOwner, address indexed to, uint256 amount);
  event InitiateJobTransfer(bytes32 indexed jobKey, address indexed from, address indexed to);
  event AcceptJobTransfer(bytes32 indexed jobKey_, address indexed to_);
  event SetJobConfig(bytes32 indexed jobKey, bool isActive_, bool useJobOwnerCredits_, bool assertResolverSelector_);
  event SetJobResolver(bytes32 indexed jobKey, address resolverAddress, bytes resolverCalldata);
  event SetJobPreDefinedCalldata(bytes32 indexed jobKey, bytes preDefinedCalldata);
  event SetAgentParams(uint256 minKeeperCvp_, uint256 timeoutSeconds_, uint256 feePct_);
  event RegisterJob(
    bytes32 indexed jobKey,
    address indexed jobAddress,
    uint256 indexed jobId,
    address owner,
    RegisterJobParams params
  );
  event JobUpdate(
    bytes32 indexed jobKey,
    uint256 maxBaseFeeGwei,
    uint256 rewardPct,
    uint256 fixedReward,
    uint256 jobMinCvp,
    uint256 intervalSeconds
  );

  struct Keeper {
    address worker;
    uint96 cvpStake;
  }

  uint256 internal minKeeperCvp;
  uint256 internal pendingWithdrawalTimeoutSeconds;
  uint256 internal feeTotal;
  uint256 internal feePpm;
  uint256 internal lastKeeperId;

  // keccak256(jobAddress, id) => ethBalance
  mapping(bytes32 => Job) internal jobs;
  // keccak256(jobAddress, id) => customCalldata
  mapping(bytes32 => bytes) internal preDefinedCalldatas;
  // keccak256(jobAddress, id) => minKeeperCvpStake
  mapping(bytes32 => uint256) internal jobMinKeeperCvp;
  // keccak256(jobAddress, id) => owner
  mapping(bytes32 => address) internal jobOwners;
  // keccak256(jobAddress, id) => resolver(address,calldata)
  mapping(bytes32 => Resolver) internal resolvers;
  // keccak256(jobAddress, id) => pendingAddress
  mapping(bytes32 => address) internal jobPendingTransfers;

  // jobAddress => lastIdRegistered(actually uint24)
  mapping(address => uint256) public jobLastIds;

  // keeperId => (worker,CVP stake)
  mapping(uint256 => Keeper) internal keepers;
  // keeperId => admin
  mapping(uint256 => address) internal keeperAdmins;
  // keeperId => the slashed CVP amount
  mapping(uint256 => uint256) internal slashedStakeOf;
  // keeperId => native token compensation
  mapping(uint256 => uint256) internal compensations;

  // keeperId => pendingWithdrawalCVP amount
  mapping(uint256 => uint256) internal pendingWithdrawalAmounts;
  // keeperId => pendingWithdrawalEndsAt timestamp
  mapping(uint256 => uint256) internal pendingWithdrawalEndsAt;

  // owner => credits
  mapping(address => uint256) public jobOwnerCredits;

  // worker => keeperIs
  mapping(address => uint256) public workerKeeperIds;

  /*** PSEUDO-MODIFIERS ***/

  function _assertOnlyOwner() internal view {
    if (msg.sender != owner()) {
      revert OnlyOwner();
    }
  }

  function _assertOnlyJobOwner(bytes32 jobKey_) internal view {
    if (msg.sender != jobOwners[jobKey_]) {
      revert OnlyJobOwner();
    }
  }

  function _assertOnlyKeeperAdmin(uint256 keeperId_) internal view {
    if (msg.sender != keeperAdmins[keeperId_]) {
      revert OnlyKeeperAdmin();
    }
  }

  function _assertOnlyKeeperAdminOrWorker(uint256 keeperId_) internal view {
    if (msg.sender != keeperAdmins[keeperId_] && msg.sender != keepers[keeperId_].worker) {
      revert OnlyKeeperAdminOrWorker();
    }
  }

  function _assertWorkerNotAssigned(address worker_) internal view {
    if (workerKeeperIds[worker_] != 0) {
      revert WorkerAlreadyAssigned();
    }
  }

  function _assertNonZeroAmount(uint256 amount_) internal pure {
    if (amount_ == 0) {
      revert MissingAmount();
    }
  }

  function _assertNonZeroValue() internal view {
    if (msg.value == 0) {
      revert MissingDeposit();
    }
  }

  function _assertJobCalldataSource(bytes32 jobKey_, CalldataSourceType source_) internal view {
    if (CalldataSourceType(jobs[jobKey_].calldataSource) != source_) {
      revert NotSupportedByJobCalldataSource();
    }
  }

  function _assertJobParams(uint256 maxBaseFeeGwei_, uint256 fixedReward_, uint256 rewardPct_) internal pure {
    if (maxBaseFeeGwei_ == 0) {
      revert MissingMaxBaseFeeGwei();
    }

    if (fixedReward_ == 0 && rewardPct_ == 0) {
      revert NoFixedNorPremiumPctReward();
    }
  }

  function _assertInterval(uint256 interval_, CalldataSourceType calldataSource_) internal pure {
    if (interval_ == 0 &&
      (calldataSource_ == CalldataSourceType.SELECTOR || calldataSource_ == CalldataSourceType.PRE_DEFINED)) {
      revert JobShouldHaveInterval();
    }
  }

  constructor(address owner_, address cvp_, uint256 minKeeperCvp_, uint256 pendingWithdrawalTimeoutSeconds_) {
    minKeeperCvp = minKeeperCvp_;
    CVP = IERC20(cvp_);
    pendingWithdrawalTimeoutSeconds = pendingWithdrawalTimeoutSeconds_;
    _transferOwnership(owner_);
  }

  /*** UPKEEP INTERFACE ***/

  /**
   * Executes a job.
   * The method arguments a tightly coupled with a custom layout in order to save some gas.
   * The calldata has the following layout :
   *  0x      00000000 1b48315d66ba5267aac8d0ab63c49038b56b1dbc 0000f1 03     00001a    402b2eed11
   *  name    selector jobContractAddress                       jobId  config keeperId  calldata (optional)
   *  size b  bytes4   bytes20                                  uint24 uint8  uint24    any
   *  size u  uint32   uint160                                  bytes3 bytes1 bytes3    any
   *  bits    0-3      4-23                                     24-26  27-27  28-30     31+
   */
  function execute_44g58pv() external {
    uint256 gasStart = gasleft();
    bytes32 jobKey;

    assembly ("memory-safe") {
      // size of (address(bytes20)+id(uint24/bytes3))
      let size := 23

      // keccack256(address+id(uint24)) to memory to generate jobKey
      calldatacopy(0, 4, size)
      jobKey := keccak256(0, size)
    }

    address jobAddress;
    uint256 keeperId;
    uint256 cfg;

    assembly ("memory-safe") {
      // load jobAddress, cfg, and keeperId from calldata to the stack
      jobAddress := shr(96, calldataload(4))
      cfg := shr(248, calldataload(27))
      keeperId := shr(232, calldataload(28))
    }

    // 0. Keeper has sufficient stake
    {
      Keeper memory keeper = keepers[keeperId];
      if (keeper.worker != msg.sender) {
        revert KeeperWorkerNotAuthorized();
      }
      if (keeper.cvpStake < minKeeperCvp) {
        revert InsufficientKeeperStake();
      }
    }

    uint256 binJob = getJobRaw(jobKey);

    // 1. Assert the job is active
    {
      if (!ConfigFlags.check(binJob, CFG_ACTIVE)) {
        revert InactiveJob(jobKey);
      }
    }

    // 2. Assert job-scoped keeper's minimum CVP deposit
    if (ConfigFlags.check(binJob, CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT) && keepers[keeperId].cvpStake < jobMinKeeperCvp[jobKey]) {
      revert InsufficientJobScopedKeeperStake();
    }

    // 3. For interval job ensure the interval has passed
    {
      uint256 intervalSeconds = (binJob << 32) >> 232;

      if (intervalSeconds > 0) {
        uint256 lastExecutionAt = binJob >> 224;
        if (lastExecutionAt > 0) {
          uint256 nextExecutionAt;
          unchecked {
            nextExecutionAt = lastExecutionAt + intervalSeconds;
          }
          if (nextExecutionAt > block.timestamp) {
            revert IntervalNotReached(lastExecutionAt, intervalSeconds, block.timestamp);
          }
        }
      }
    }

    // 4. Ensure gas price fits base fee
    uint256 maxBaseFee;
    {
      unchecked {
        maxBaseFee = ((binJob << 112) >> 240)  * 1 gwei;
      }
      if (block.basefee > maxBaseFee && !ConfigFlags.check(cfg, FLAG_ACCEPT_MAX_BASE_FEE_LIMIT)) {
        revert BaseFeeGtGasPrice(block.basefee, maxBaseFee);
      }
    }

    // 5. Ensure msg.sender is EOA
    if (msg.sender != tx.origin) {
      revert NonEOASender();
    }

    bool ok;
    uint256 jobGas = gasleft() - 50_000;

    // Source: Selector
    CalldataSourceType calldataSource = CalldataSourceType((binJob << 56) >> 248);
    if (calldataSource == CalldataSourceType.SELECTOR) {
      bytes4 selector;
      assembly {
        selector := shl(224, shr(8, binJob))
      }
      (ok,) = jobAddress.call{ gas: jobGas }(abi.encode(selector));
    // Source: Bytes
    } else if (calldataSource == CalldataSourceType.PRE_DEFINED) {
      (ok,) = jobAddress.call{ gas: jobGas }(preDefinedCalldatas[jobKey]);
    // Source: Resolver
    } else if (calldataSource == CalldataSourceType.RESOLVER) {
      assembly ("memory-safe") {
        let cdInCdSize := calldatasize()
        // calldata offset is 31
        let beforeCdSize := 31
        let ptr := mload(0x40)
        if lt(cdInCdSize, beforeCdSize) {
          // revert MissingInputCalldata()
          mstore(ptr, 0x47a0bafb00000000000000000000000000000000000000000000000000000000)
          revert(ptr, 4)
        }
        let cdSize := sub(cdInCdSize, beforeCdSize)
        mstore(0x40, add(ptr, cdSize))
        calldatacopy(ptr, beforeCdSize, cdSize)
        // CFG_ASSERT_RESOLVER_SELECTOR = 0x04 from PPAgentLiteFlags
        if and(binJob, 0x04) {
          if iszero(eq(
            // actual
            shl(224, shr(224, calldataload(31))),
            // expected
            shl(224, shr(8, binJob))
          )) {
            // revert SelectorCheckFailed()
            mstore(ptr, 0x84fb827500000000000000000000000000000000000000000000000000000000)
            revert(ptr, 4)
          }
        }
        // The remaining gas could not be less than 50_000
        ok := call(jobGas, jobAddress, 0, ptr, cdSize, 0x0, 0x0)
      }
    } else {
      // Should never be reached
      revert InvalidCalldataSource();
    }

    // Transaction succeeded
    if (ok) {
      binJob = getJobRaw(jobKey);
      uint256 gasUsed;
      unchecked {
        gasUsed = gasStart - gasleft();
      }

      uint256 compensation;
      {
        uint256 min = block.basefee;
        if (maxBaseFee < min) {
          min = maxBaseFee;
        }

        compensation = _calculateCompensation(binJob, min, gasUsed);
      }
      {
        bool jobChanged;

        if (ConfigFlags.check(binJob, CFG_USE_JOB_OWNER_CREDITS)) {
          // use job owner credits
          _useJobOwnerCredits(jobKey, compensation);
        } else {
          // use job credits
          uint256 creditsBefore = (binJob << 128) >> 168;
          if (creditsBefore < compensation) {
            revert InsufficientJobCredits(creditsBefore, compensation);
          }

          uint256 creditsAfter;
          unchecked {
            creditsAfter = creditsBefore - compensation;
          }
          // update job credits
          binJob = binJob & BM_CLEAR_CREDITS | (creditsAfter << 40);
          jobChanged = true;
        }

        if (ConfigFlags.check(cfg, FLAG_ACCRUE_REWARD)) {
          compensations[keeperId] += compensation;
        } else {
          payable(msg.sender).transfer(compensation);
        }

        // Update lastExecutionAt for interval jobs
        {
          uint256 intervalSeconds = (binJob << 32) >> 232;
          if (intervalSeconds > 0) {
            uint256 lastExecutionAt = uint32(block.timestamp);
            binJob = binJob & BM_CLEAR_LAST_UPDATE_AT | (lastExecutionAt << 224);
            jobChanged = true;
          }
        }

        if (jobChanged) {
          _updateRawJob(jobKey, binJob);
        }
      }

      emit Execute(
        jobKey,
        jobAddress,
        keeperId,
        gasUsed,
        block.basefee,
        tx.gasprice,
        compensation,
        bytes32(binJob)
      );
    // Tx reverted
    } else {
      uint256 size;
      assembly ("memory-safe") {
        size := returndatasize()
      }

      if (size == 0) {
        revert JobCallRevertedWithoutDetails();
      }

      assembly ("memory-safe") {
        let p := mload(0x40)
        returndatacopy(p, 0, size)
        revert(p, size)
      }
    }
  }

  function _calculateCompensation(uint256 job_, uint256 gasPrice_, uint256 gasUsed_) internal pure returns (uint256) {
    uint256 fixedReward = (job_ << 64) >> 224;
    uint256 rewardPct = (job_ << 96) >> 240;
    return calculateCompensationPure(rewardPct, fixedReward, gasPrice_, gasUsed_);
  }

  function _useJobOwnerCredits(bytes32 jobKey_, uint256 compensation_) internal {
    uint256 jobOwnerCreditsBefore = jobOwnerCredits[jobOwners[jobKey_]];
    if (jobOwnerCreditsBefore < compensation_) {
      revert InsufficientJobOwnerCredits(jobOwnerCreditsBefore, compensation_);
    }

    unchecked {
      jobOwnerCredits[jobOwners[jobKey_]] = jobOwnerCreditsBefore - compensation_;
    }
  }

  struct RegisterJobParams {
    address jobAddress;
    bytes4 jobSelector;
    bool useJobOwnerCredits;
    bool assertResolverSelector;
    uint16 maxBaseFeeGwei;
    uint16 rewardPct;
    uint32 fixedReward;
    uint256 jobMinCvp;
    uint8 calldataSource;
    uint24 intervalSeconds;
  }

  /*** JOB OWNER INTERFACE ***/

  /**
   * Registers a new job.
   *
   * Job id is unique counter for a given job address. Up to 2**24-1 jobs per address.
   * Job key is a keccak256(address, jobId).
   * The following options are immutable:
   *  - `params_.jobaddress`
   *  - `params_.calldataSource`
   * If you need to modify one of the immutable options above later consider creating a new job.
   *
   * @param params_ Job-specific params
   * @param resolver_ Resolver details(address, calldata), required only for CALLDATA_SOURCE_RESOLVER
   *                  job type. Use empty values for the other job types.
   * @param preDefinedCalldata_ Calldata to call a job with, required only for CALLDATA_SOURCE_PRE_DEFINED
   *              job type. Keep empty for the other job types.
   */
  function registerJob(
    RegisterJobParams calldata params_,
    Resolver calldata resolver_,
    bytes calldata preDefinedCalldata_
  ) external payable returns (bytes32 jobKey, uint256 jobId){
    jobId = jobLastIds[params_.jobAddress] + 1;

    if (jobId > type(uint24).max) {
      revert JobIdOverflow();
    }

    if (msg.value > type(uint88).max) {
      revert CreditsDepositOverflow();
    }

    if (params_.jobAddress == address(0)) {
      revert MissingJobAddress();
    }

    if (params_.calldataSource > 2) {
      revert InvalidCalldataSource();
    }

    if (params_.jobAddress == address(CVP)) {
      revert InvalidJobAddress();
    }

    _assertInterval(params_.intervalSeconds, CalldataSourceType(params_.calldataSource));
    _assertJobParams(params_.maxBaseFeeGwei, params_.fixedReward, params_.rewardPct);
    jobKey = getJobKey(params_.jobAddress, jobId);

    emit RegisterJob(
      jobKey,
      params_.jobAddress,
      jobId,
      msg.sender,
      params_
    );

    if (CalldataSourceType(params_.calldataSource) == CalldataSourceType.PRE_DEFINED) {
      _setJobPreDefinedCalldata(jobKey, preDefinedCalldata_);
    } else if (CalldataSourceType(params_.calldataSource) == CalldataSourceType.RESOLVER) {
      _setJobResolver(jobKey, resolver_);
    }

    {
      bytes4 selector = 0x00000000;
      if (CalldataSourceType(params_.calldataSource) != CalldataSourceType.PRE_DEFINED) {
        selector = params_.jobSelector;
      }

      uint256 config = CFG_ACTIVE;
      if (params_.useJobOwnerCredits) {
        config = config | CFG_USE_JOB_OWNER_CREDITS;
      }
      if (params_.assertResolverSelector) {
        config = config | CFG_ASSERT_RESOLVER_SELECTOR;
      }
      if (params_.jobMinCvp > 0) {
        config = config | CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT;
      }

      jobs[jobKey] = Job({
        config: uint8(config),
        selector: selector,
        credits: 0,
        maxBaseFeeGwei: params_.maxBaseFeeGwei,
        fixedReward: params_.fixedReward,
        rewardPct: params_.rewardPct,
        calldataSource: params_.calldataSource,

        // For interval jobs
        intervalSeconds: params_.intervalSeconds,
        lastExecutionAt: 0
      });
      jobMinKeeperCvp[jobKey] = params_.jobMinCvp;
    }

    jobLastIds[params_.jobAddress] = jobId;
    jobOwners[jobKey] = msg.sender;

    if (msg.value > 0) {
      if (params_.useJobOwnerCredits) {
        _processJobOwnerCreditsDeposit(msg.sender);
      } else {
        _processJobCreditsDeposit(jobKey);
      }
    }
  }

  /**
   * Updates a job details.
   *
   * The following options are immutable:
   *  - `jobAddress`
   *  - `job.selector`
   *  - `job.calldataSource`
   * If you need to modify one of the immutable options above later consider creating a new job.
   *
   * @param jobKey_ The job key
   * @param maxBaseFeeGwei_ The maximum basefee in gwei to use for a job compensation
   * @param rewardPct_ The reward premium in pct, where 1 == 1%
   * @param fixedReward_ The fixed reward divided by FIXED_PAYMENT_MULTIPLIER
   * @param jobMinCvp_ The keeper minimal CVP stake to be eligible to execute this job
   * @param intervalSeconds_ The interval for a job execution
   */
  function updateJob(
    bytes32 jobKey_,
    uint16 maxBaseFeeGwei_,
    uint16 rewardPct_,
    uint32 fixedReward_,
    uint256 jobMinCvp_,
    uint24 intervalSeconds_
  ) external {
    _assertOnlyJobOwner(jobKey_);
    _assertJobParams(maxBaseFeeGwei_, fixedReward_, rewardPct_);

    Job memory job = jobs[jobKey_];

    _assertInterval(intervalSeconds_, CalldataSourceType(job.calldataSource));

    uint256 cfg = job.config;

    if (jobMinCvp_ > 0 && !ConfigFlags.check(job.config, CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT)) {
      cfg = cfg | CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT;
    }
    if (jobMinCvp_ == 0 && ConfigFlags.check(job.config, CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT)) {
      cfg = cfg ^ CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT;
    }

    jobs[jobKey_].config = uint8(cfg);
    jobMinKeeperCvp[jobKey_] = jobMinCvp_;

    jobs[jobKey_].maxBaseFeeGwei = maxBaseFeeGwei_;
    jobs[jobKey_].rewardPct = rewardPct_;
    jobs[jobKey_].fixedReward = fixedReward_;
    jobs[jobKey_].intervalSeconds = intervalSeconds_;

    emit JobUpdate(jobKey_, maxBaseFeeGwei_, rewardPct_, fixedReward_, jobMinCvp_, intervalSeconds_);
  }

  /**
   * A job owner updates job resolver details.
   *
   * @param jobKey_ The jobKey
   * @param resolver_ The new job resolver details
   */
  function setJobResolver(bytes32 jobKey_, Resolver calldata resolver_) external {
    _assertOnlyJobOwner(jobKey_);
    _assertJobCalldataSource(jobKey_, CalldataSourceType.RESOLVER);

    _setJobResolver(jobKey_, resolver_);
  }

  function _setJobResolver(bytes32 jobKey_, Resolver calldata resolver_) internal {
    if (resolver_.resolverAddress == address(0)) {
      revert MissingResolverAddress();
    }
    resolvers[jobKey_] = resolver_;
    emit SetJobResolver(jobKey_, resolver_.resolverAddress, resolver_.resolverCalldata);
  }

  /**
   * A job owner updates pre-defined calldata.
   *
   * @param jobKey_ The jobKey
   * @param preDefinedCalldata_ The new job pre-defined calldata
   */
  function setJobPreDefinedCalldata(bytes32 jobKey_, bytes calldata preDefinedCalldata_) external {
    _assertOnlyJobOwner(jobKey_);
    _assertJobCalldataSource(jobKey_, CalldataSourceType.PRE_DEFINED);

    _setJobPreDefinedCalldata(jobKey_, preDefinedCalldata_);
  }

  function _setJobPreDefinedCalldata(bytes32 jobKey_, bytes calldata preDefinedCalldata_) internal {
    preDefinedCalldatas[jobKey_] = preDefinedCalldata_;
    emit SetJobPreDefinedCalldata(jobKey_, preDefinedCalldata_);
  }

  /**
   * A job owner updates a job config flag.
   *
   * @param jobKey_ The jobKey
   * @param isActive_ Whether the job is active or not
   * @param useJobOwnerCredits_ The useJobOwnerCredits flag
   * @param assertResolverSelector_ The assertResolverSelector flag
   */
  function setJobConfig(
    bytes32 jobKey_,
    bool isActive_,
    bool useJobOwnerCredits_,
    bool assertResolverSelector_
  ) external {
    _assertOnlyJobOwner(jobKey_);
    uint256 newConfig = 0;

    if (isActive_) {
      newConfig = newConfig | CFG_ACTIVE;
    }
    if (useJobOwnerCredits_) {
      newConfig = newConfig | CFG_USE_JOB_OWNER_CREDITS;
    }
    if (assertResolverSelector_) {
      newConfig = newConfig | CFG_ASSERT_RESOLVER_SELECTOR;
    }

    uint256 job = getJobRaw(jobKey_) & BM_CLEAR_CONFIG | newConfig;
    _updateRawJob(jobKey_, job);

    emit SetJobConfig(jobKey_, isActive_, useJobOwnerCredits_, assertResolverSelector_);
  }

  function _updateRawJob(bytes32 jobKey_, uint256 job_) internal {
    Job storage job = jobs[jobKey_];
    assembly {
      sstore(job.slot, job_)
    }
  }

  /**
   * A job owner initiates the job transfer to a new owner.
   * The actual owner doesn't update until the pending owner accepts the transfer.
   *
   * @param jobKey_ The jobKey
   * @param to_ The new job owner
   */
  function initiateJobTransfer(bytes32 jobKey_, address to_) external {
    _assertOnlyJobOwner(jobKey_);
    jobPendingTransfers[jobKey_] = to_;
    emit InitiateJobTransfer(jobKey_, msg.sender, to_);
  }

  /**
   * A pending job owner accepts the job transfer.
   *
   * @param jobKey_ The jobKey
   */
  function acceptJobTransfer(bytes32 jobKey_) external {
    if (msg.sender != jobPendingTransfers[jobKey_]) {
      revert OnlyPendingOwner();
    }

    jobOwners[jobKey_] = msg.sender;
    delete jobPendingTransfers[jobKey_];

    emit AcceptJobTransfer(jobKey_, msg.sender);
  }

  /**
   * Top-ups the job credits in NATIVE tokens.
   *
   * @param jobKey_ The jobKey to deposit for
   */
  function depositJobCredits(bytes32 jobKey_) external payable {
    _assertNonZeroValue();

    if (jobOwners[jobKey_] == address(0)) {
      revert JobWithoutOwner();
    }

    _processJobCreditsDeposit(jobKey_);
  }

  function _processJobCreditsDeposit(bytes32 jobKey_) internal {
    (uint256 fee, uint256 amount) = _calculateDepositFee();
    uint256 creditsAfter = jobs[jobKey_].credits + amount;
    if (creditsAfter > type(uint88).max) {
      revert CreditsDepositOverflow();
    }

    unchecked {
      feeTotal += fee;
    }
    jobs[jobKey_].credits = uint88(creditsAfter);

    emit DepositJobCredits(jobKey_, msg.sender, amount, fee);
  }

  function _calculateDepositFee() internal view returns (uint256 fee, uint256 amount) {
    fee = msg.value * feePpm / 1e6 /* 100% in ppm */;
    amount = msg.value - fee;
  }

  /**
   * A job owner withdraws the job credits in NATIVE tokens.
   *
   * @param jobKey_ The jobKey
   * @param to_ The address to send NATIVE tokens to
   * @param amount_ The amount to withdraw. Use type(uint256).max for the total available credits withdrawal.
   */
  function withdrawJobCredits(
    bytes32 jobKey_,
    address payable to_,
    uint256 amount_
  ) external {
    uint88 creditsBefore = jobs[jobKey_].credits;
    if (amount_ == type(uint256).max) {
      amount_ = creditsBefore;
    }

    _assertOnlyJobOwner(jobKey_);
    _assertNonZeroAmount(amount_);

    if (creditsBefore < amount_) {
      revert CreditsWithdrawalUnderflow();
    }

    unchecked {
      jobs[jobKey_].credits = creditsBefore - uint88(amount_);
    }

    to_.transfer(amount_);

    emit WithdrawJobCredits(jobKey_, msg.sender, to_, amount_);
  }

  /**
   * Top-ups the job owner credits in NATIVE tokens.
   *
   * @param for_ The job owner address to deposit for
   */
  function depositJobOwnerCredits(address for_) external payable {
    _assertNonZeroValue();

    _processJobOwnerCreditsDeposit(for_);
  }

  function _processJobOwnerCreditsDeposit(address for_) internal {
    (uint256 fee, uint256 amount) = _calculateDepositFee();

    unchecked {
      feeTotal += fee;
      jobOwnerCredits[for_] += amount;
    }

    emit DepositJobOwnerCredits(for_, msg.sender, amount, fee);
  }

  /**
   * A job owner withdraws the job owner credits in NATIVE tokens.
   *
   * @param to_ The address to send NATIVE tokens to
   * @param amount_ The amount to withdraw. Use type(uint256).max for the total available credits withdrawal.
   */
  function withdrawJobOwnerCredits(address payable to_, uint256 amount_) external {
    uint256 creditsBefore = jobOwnerCredits[msg.sender];
    if (amount_ == type(uint256).max) {
      amount_ = creditsBefore;
    }

    _assertNonZeroAmount(amount_);

    if (creditsBefore < amount_) {
      revert CreditsWithdrawalUnderflow();
    }

    unchecked {
      jobOwnerCredits[msg.sender] = creditsBefore - amount_;
    }

    to_.transfer(amount_);

    emit WithdrawJobOwnerCredits(msg.sender, to_, amount_);
  }

  /*** KEEPER INTERFACE ***/

  /**
   * Actor registers as a keeper.
   * One keeper address could have multiple keeper IDs. Requires at least `minKeepCvp` as an initial CVP deposit.
   *
   * @dev Overflow-safe only for CVP which total supply is less than type(uint96).max
   * @dev Maximum 2^24-1 keepers supported. There is no explicit check for overflow, but the keepers with ID >= 2^24
   *         won't be able to perform upkeep operations.
   *
   * @param worker_ The worker address
   * @param initialDepositAmount_ The initial CVP deposit. Should be no less than `minKeepCvp`
   * @return keeperId The registered keeper ID
   */
  function registerAsKeeper(address worker_, uint256 initialDepositAmount_) external returns (uint256 keeperId) {
    _assertWorkerNotAssigned(worker_);

    if (initialDepositAmount_ < minKeeperCvp) {
      revert InsufficientAmount();
    }

    keeperId = ++lastKeeperId;
    keeperAdmins[keeperId] = msg.sender;
    keepers[keeperId] = Keeper(worker_, 0);
    workerKeeperIds[worker_] = keeperId;
    emit RegisterAsKeeper(keeperId, msg.sender, worker_);

    _stake(keeperId, initialDepositAmount_);
  }

  /**
   * A keeper updates a keeper worker address
   *
   * @param keeperId_ The keeper ID
   * @param worker_ The new worker address
   */
  function setWorkerAddress(uint256 keeperId_, address worker_) external {
    _assertOnlyKeeperAdmin(keeperId_);
    _assertWorkerNotAssigned(worker_);

    address prev = keepers[keeperId_].worker;
    delete workerKeeperIds[prev];
    workerKeeperIds[worker_] = keeperId_;
    keepers[keeperId_].worker = worker_;

    emit SetWorkerAddress(keeperId_, prev, worker_);
  }

  /**
   * A keeper withdraws NATIVE token rewards.
   *
   * @param keeperId_ The keeper ID
   * @param to_ The address to withdraw to
   * @param amount_ The amount to withdraw. Use type(uint256).max for the total available compensation withdrawal.
   */
  function withdrawCompensation(uint256 keeperId_, address payable to_, uint256 amount_) external {
    uint256 available = compensations[keeperId_];
    if (amount_ == type(uint256).max) {
      amount_ = available;
    }

    _assertNonZeroAmount(amount_);
    _assertOnlyKeeperAdminOrWorker(keeperId_);

    if (amount_ > available) {
      revert WithdrawAmountExceedsAvailable(amount_, available);
    }

    unchecked {
      compensations[keeperId_] = available - amount_;
    }

    to_.transfer(amount_);

    emit WithdrawCompensation(keeperId_, to_, amount_);
  }

  /**
   * Deposits CVP for the given keeper ID. The beneficiary receives a derivative erc20 token in exchange of CVP.
   *   Accounts the staking amount on the beneficiary's stakeOf balance.
   *
   * @param keeperId_ The keeper ID
   * @param amount_ The amount to stake
   */
  function stake(uint256 keeperId_, uint256 amount_) external {
    _assertNonZeroAmount(amount_);
    _stake(keeperId_, amount_);
  }

  function _stake(uint256 keeperId_, uint256 amount_) internal {
    CVP.transferFrom(msg.sender, address(this), amount_);
    keepers[keeperId_].cvpStake += uint96(amount_);

    emit Stake(keeperId_, amount_, msg.sender);
  }

  /**
   * A keeper initiates CVP withdrawal.
   * The given CVP amount needs to go through the cooldown stage. After the cooldown is complete this amount could be
   * withdrawn using `finalizeRedeem()` method.
   * The msg.sender burns the paCVP token in exchange of the corresponding CVP amount.
   * Accumulates the existing pending for withdrawal amounts and re-initiates cooldown period.
   * If there is any slashed amount for the msg.sender, it should be compensated within the first initiateRedeem transaction
   * by burning the equivalent amount of paCVP tokens. The remaining CVP tokens won't be redeemed unless the slashed
   * amount is compensated.
   *
   * @param keeperId_ The keeper ID
   * @param amount_ The amount to cooldown
   * @return pendingWithdrawalAfter The total pending for withdrawal amount
   */
  function initiateRedeem(uint256 keeperId_, uint256 amount_) external returns (uint256 pendingWithdrawalAfter) {
    _assertOnlyKeeperAdmin(keeperId_);
    _assertNonZeroAmount(amount_);

    uint256 stakeOfBefore = keepers[keeperId_].cvpStake;
    uint256 slashedStakeOfBefore = slashedStakeOf[keeperId_];
    uint256 totalStakeBefore = stakeOfBefore + slashedStakeOfBefore;

    // Should burn at least the total slashed stake
    if (amount_ < slashedStakeOfBefore) {
      revert InsufficientAmountToCoverSlashedStake(amount_, slashedStakeOfBefore);
    }

    if (amount_ > totalStakeBefore) {
      revert AmountGtStake(amount_, stakeOfBefore, slashedStakeOfBefore);
    }

    slashedStakeOf[keeperId_] = 0;
    uint256 stakeOfToReduceAmount;
    unchecked {
      stakeOfToReduceAmount = amount_ - slashedStakeOfBefore;
      keepers[keeperId_].cvpStake = uint96(stakeOfBefore - stakeOfToReduceAmount);
      pendingWithdrawalAmounts[keeperId_] += stakeOfToReduceAmount;
    }

    pendingWithdrawalAfter = block.timestamp + pendingWithdrawalTimeoutSeconds;
    pendingWithdrawalEndsAt[keeperId_] = pendingWithdrawalAfter;

    emit InitiateRedeem(keeperId_, amount_, stakeOfToReduceAmount, slashedStakeOfBefore);
  }

  /**
   * A keeper finalizes CVP withdrawal and receives the staked CVP tokens.
   *
   * @param keeperId_ The keeper ID
   * @param to_ The address to transfer CVP to
   * @return redeemedCvp The redeemed CVP amount
   */
  function finalizeRedeem(uint256 keeperId_, address to_) external returns (uint256 redeemedCvp) {
    _assertOnlyKeeperAdmin(keeperId_);

    if (pendingWithdrawalEndsAt[keeperId_] > block.timestamp) {
      revert WithdrawalTimoutNotReached();
    }

    redeemedCvp = pendingWithdrawalAmounts[keeperId_];
    if (redeemedCvp == 0) {
      revert NoPendingWithdrawal();
    }

    pendingWithdrawalAmounts[keeperId_] = 0;
    CVP.transfer(to_, redeemedCvp);

    emit FinalizeRedeem(keeperId_, to_, redeemedCvp);
  }

  /*** CONTRACT OWNER INTERFACE ***/
  /**
   * Slashes any keeper_ for an amount within keeper's deposit.
   * Penalises a keeper for malicious behaviour like sandwitching upkeep transactions.
   *
   * @param keeperId_ The keeper ID to slash
   * @param to_ The address to send the slashed CVP to
   * @param currentAmount_ The amount to slash from the current keeper.cvpStake balance
   * @param pendingAmount_ The amount to slash from the pendingWithdrawals balance
   */
  function slash(uint256 keeperId_, address to_, uint256 currentAmount_, uint256 pendingAmount_) external {
    _assertOnlyOwner();
    uint256 totalAmount = currentAmount_ + pendingAmount_;
    _assertNonZeroAmount(totalAmount);

    if (currentAmount_ > 0) {
      keepers[keeperId_].cvpStake -= uint96(currentAmount_);
      slashedStakeOf[keeperId_] += currentAmount_;
    }

    if (pendingAmount_ > 0) {
      pendingWithdrawalAmounts[keeperId_] -= pendingAmount_;
    }

    CVP.transfer(to_, totalAmount);

    emit Slash(keeperId_, to_, currentAmount_, pendingAmount_);
  }

  /**
   * Owner withdraws all the accrued rewards in native tokens to the provided address.
   *
   * @param to_ The address to send rewards to
   */
  function withdrawFees(address payable to_) external {
    _assertOnlyOwner();

    uint256 amount = feeTotal;
    feeTotal = 0;

    to_.transfer(amount);

    emit WithdrawFees(to_, amount);
  }

  /**
   * Owner updates minKeeperCVP value
   *
   * @param minKeeperCvp_ The new minKeeperCVP value
   */
  function setAgentParams(
    uint256 minKeeperCvp_,
    uint256 timeoutSeconds_,
    uint256 feePpm_
  ) external {
    _assertOnlyOwner();

    if (timeoutSeconds_ > MAX_PENDING_WITHDRAWAL_TIMEOUT_SECONDS) {
      revert TimeoutTooBig();
    }
    if (feePpm_ > MAX_FEE_PPM) {
      revert FeeTooBig();
    }

    minKeeperCvp = minKeeperCvp_;
    pendingWithdrawalTimeoutSeconds = timeoutSeconds_;
    feePpm = feePpm_;

    emit SetAgentParams(minKeeperCvp_, timeoutSeconds_, feePpm_);
  }

  /*** GETTERS ***/

  /**
   * Pure method that calculates keeper compensation based on a dynamic and a fixed multipliers.
   * DANGER: could overflow when used externally
   *
   * @param rewardPct_ The fixed percent. uint16. 0 == 0%, 100 == 100%, 500 == 500%, max 56535 == 56535%
   * @param fixedReward_ The fixed reward. uint32. Always multiplied by 1e15 (FIXED_PAYMENT_MULTIPLIER).
   *                     For ex. 2 == 2e15, 1_000 = 1e18, max 4294967295 == 4_294_967.295e18
   * @param blockBaseFee_ The block.basefee value.
   * @param gasUsed_ The gas used in wei.
   *
   */
  function calculateCompensationPure(
    uint256 rewardPct_,
    uint256 fixedReward_,
    uint256 blockBaseFee_,
    uint256 gasUsed_
  ) public pure returns (uint256) {
    unchecked {
      return (gasUsed_ + JOB_RUN_GAS_OVERHEAD) * blockBaseFee_ * rewardPct_ / 100
             + fixedReward_ * FIXED_PAYMENT_MULTIPLIER;
    }
  }

  function getKeeperWorkerAndStake(uint256 keeperId_)
    external view returns (
      address worker,
      uint256 currentStake
    )
  {
    Keeper memory keeper = keepers[keeperId_];

    return (
      keeper.worker,
      keeper.cvpStake
    );
  }

  function getConfig()
    external view returns (
      uint256 minKeeperCvp_,
      uint256 pendingWithdrawalTimeoutSeconds_,
      uint256 feeTotal_,
      uint256 feePpm_,
      uint256 lastKeeperId_
    )
  {
    return (
      minKeeperCvp,
      pendingWithdrawalTimeoutSeconds,
      feeTotal,
      feePpm,
      lastKeeperId
    );
  }

  function getKeeper(uint256 keeperId_)
    external view returns (
      address admin,
      address worker,
      uint256 currentStake,
      uint256 slashedStake,
      uint256 compensation,
      uint256 pendingWithdrawalAmount,
      uint256 pendingWithdrawalEndAt
    )
  {
    return (
      keeperAdmins[keeperId_],
      keepers[keeperId_].worker,
      keepers[keeperId_].cvpStake,
      slashedStakeOf[keeperId_],
      compensations[keeperId_],
      pendingWithdrawalAmounts[keeperId_],
      pendingWithdrawalEndsAt[keeperId_]
    );
  }

  function getJob(bytes32 jobKey_)
    external view returns (
      address owner,
      address pendingTransfer,
      uint256 jobLevelMinKeeperCvp,
      Job memory details,
      bytes memory preDefinedCalldata,
      Resolver memory resolver
    )
  {
    return (
      jobOwners[jobKey_],
      jobPendingTransfers[jobKey_],
      jobMinKeeperCvp[jobKey_],
      jobs[jobKey_],
      preDefinedCalldatas[jobKey_],
      resolvers[jobKey_]
    );
  }

  /**
   * Returns the principal job data stored in a single EVM slot.
   * @notice To get parsed job data use `getJob()` method instead.
   *
   * The job slot data layout:
   *  0x0000000000000a000000000a002300640000000de0b6b3a7640000d09de08a01
   *  0x      00000000   00000a   00             0000000a    0023      0064           0000000de0b6b3a7640000 d09de08a 01
   *  name    lastExecAt interval calldataSource fixedReward rewardPct maxBaseFeeGwei nativeCredits          selector config bitmask
   *  size b  bytes4     bytes3   bytes4         bytes4      bytes2    bytes2         bytes11                bytes4   bytes1
   *  size u  uint32     uint24   uint8          uint32      uint16    uint16         uint88                 uint32   uint8
   *  bits    0-3        4-6      7-7            8-11        12-13     14-15          16-26                  27-30    31-31
   */
  function getJobRaw(bytes32 jobKey_) public view returns (uint256 rawJob) {
    Job storage job = jobs[jobKey_];
    assembly {
      rawJob := sload(job.slot)
    }
  }

  function getJobKey(address jobAddress_, uint256 jobId_) public pure returns (bytes32 jobKey) {
    assembly {
      mstore(0, shl(96, jobAddress_))
      mstore(20, shl(232, jobId_))
      jobKey := keccak256(0, 23)
    }
  }
}

File 2 of 5 : PPAgentV2Flags.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract PPAgentV2Flags {
  // Keeper pass this flags withing execute() transaction
  uint256 internal constant FLAG_ACCEPT_MAX_BASE_FEE_LIMIT = 0x01;
  uint256 internal constant FLAG_ACCRUE_REWARD = 0x02;

  // Job owner uses CFG_* flags to configure a job options
  uint256 internal constant CFG_ACTIVE = 0x01;
  uint256 internal constant CFG_USE_JOB_OWNER_CREDITS = 0x02;
  uint256 internal constant CFG_ASSERT_RESOLVER_SELECTOR = 0x04;
  uint256 internal constant CFG_CHECK_KEEPER_MIN_CVP_DEPOSIT = 0x08;

  uint256 internal constant BM_CLEAR_CONFIG = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00;
  uint256 internal constant BM_CLEAR_CREDITS = 0xffffffffffffffffffffffffffffffff0000000000000000000000ffffffffff;
  uint256 internal constant BM_CLEAR_LAST_UPDATE_AT = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
}

File 3 of 5 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 4 of 5 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 5 of 5 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

Settings
{
  "viaIR": false,
  "optimizer": {
    "enabled": true,
    "runs": 200000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"cvp_","type":"address"},{"internalType":"uint256","name":"minKeeperCvp_","type":"uint256"},{"internalType":"uint256","name":"pendingWithdrawalTimeoutSeconds_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"wanted","type":"uint256"},{"internalType":"uint256","name":"actualStake","type":"uint256"},{"internalType":"uint256","name":"actualSlashedStake","type":"uint256"}],"name":"AmountGtStake","type":"error"},{"inputs":[{"internalType":"uint256","name":"baseFee","type":"uint256"},{"internalType":"uint256","name":"jobMaxBaseFeeGwei","type":"uint256"}],"name":"BaseFeeGtGasPrice","type":"error"},{"inputs":[],"name":"CreditsDepositOverflow","type":"error"},{"inputs":[],"name":"CreditsWithdrawalUnderflow","type":"error"},{"inputs":[],"name":"FeeTooBig","type":"error"},{"inputs":[{"internalType":"bytes32","name":"jobKey","type":"bytes32"}],"name":"InactiveJob","type":"error"},{"inputs":[],"name":"InsufficientAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"wanted","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InsufficientAmountToCoverSlashedStake","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"wanted","type":"uint256"}],"name":"InsufficientJobCredits","type":"error"},{"inputs":[{"internalType":"uint256","name":"actual","type":"uint256"},{"internalType":"uint256","name":"wanted","type":"uint256"}],"name":"InsufficientJobOwnerCredits","type":"error"},{"inputs":[],"name":"InsufficientJobScopedKeeperStake","type":"error"},{"inputs":[],"name":"InsufficientKeeperStake","type":"error"},{"inputs":[{"internalType":"uint256","name":"lastExecutedAt","type":"uint256"},{"internalType":"uint256","name":"interval","type":"uint256"},{"internalType":"uint256","name":"_now","type":"uint256"}],"name":"IntervalNotReached","type":"error"},{"inputs":[],"name":"InvalidCalldataSource","type":"error"},{"inputs":[],"name":"InvalidJobAddress","type":"error"},{"inputs":[],"name":"JobCallRevertedWithoutDetails","type":"error"},{"inputs":[],"name":"JobIdOverflow","type":"error"},{"inputs":[],"name":"JobShouldHaveInterval","type":"error"},{"inputs":[],"name":"JobWithoutOwner","type":"error"},{"inputs":[],"name":"KeeperWorkerNotAuthorized","type":"error"},{"inputs":[],"name":"MissingAmount","type":"error"},{"inputs":[],"name":"MissingDeposit","type":"error"},{"inputs":[],"name":"MissingInputCalldata","type":"error"},{"inputs":[],"name":"MissingJobAddress","type":"error"},{"inputs":[],"name":"MissingMaxBaseFeeGwei","type":"error"},{"inputs":[],"name":"MissingResolverAddress","type":"error"},{"inputs":[],"name":"NoFixedNorPremiumPctReward","type":"error"},{"inputs":[],"name":"NoPendingWithdrawal","type":"error"},{"inputs":[],"name":"NonEOASender","type":"error"},{"inputs":[],"name":"NotSupportedByJobCalldataSource","type":"error"},{"inputs":[],"name":"OnlyJobOwner","type":"error"},{"inputs":[],"name":"OnlyKeeperAdmin","type":"error"},{"inputs":[],"name":"OnlyKeeperAdminOrWorker","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"OnlyPendingOwner","type":"error"},{"inputs":[],"name":"SelectorCheckFailed","type":"error"},{"inputs":[],"name":"TimeoutTooBig","type":"error"},{"inputs":[{"internalType":"uint256","name":"wanted","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"WithdrawAmountExceedsAvailable","type":"error"},{"inputs":[],"name":"WithdrawalTimoutNotReached","type":"error"},{"inputs":[],"name":"WorkerAlreadyAssigned","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey_","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to_","type":"address"}],"name":"AcceptJobTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"DepositJobCredits","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"jobOwner","type":"address"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"DepositJobOwnerCredits","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":true,"internalType":"address","name":"job","type":"address"},{"indexed":false,"internalType":"uint256","name":"keeperId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"compensation","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"binJobAfter","type":"bytes32"}],"name":"Execute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keeperId","type":"uint256"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FinalizeRedeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"InitiateJobTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keeperId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"slashedStakeAmount","type":"uint256"}],"name":"InitiateRedeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"maxBaseFeeGwei","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPct","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fixedReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"jobMinCvp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"intervalSeconds","type":"uint256"}],"name":"JobUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keeperId","type":"uint256"},{"indexed":true,"internalType":"address","name":"keeperAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"keeperWorker","type":"address"}],"name":"RegisterAsKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":true,"internalType":"address","name":"jobAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"jobId","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"components":[{"internalType":"address","name":"jobAddress","type":"address"},{"internalType":"bytes4","name":"jobSelector","type":"bytes4"},{"internalType":"bool","name":"useJobOwnerCredits","type":"bool"},{"internalType":"bool","name":"assertResolverSelector","type":"bool"},{"internalType":"uint16","name":"maxBaseFeeGwei","type":"uint16"},{"internalType":"uint16","name":"rewardPct","type":"uint16"},{"internalType":"uint32","name":"fixedReward","type":"uint32"},{"internalType":"uint256","name":"jobMinCvp","type":"uint256"},{"internalType":"uint8","name":"calldataSource","type":"uint8"},{"internalType":"uint24","name":"intervalSeconds","type":"uint24"}],"indexed":false,"internalType":"struct PPAgentV2.RegisterJobParams","name":"params","type":"tuple"}],"name":"RegisterJob","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minKeeperCvp_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timeoutSeconds_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feePct_","type":"uint256"}],"name":"SetAgentParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"isActive_","type":"bool"},{"indexed":false,"internalType":"bool","name":"useJobOwnerCredits_","type":"bool"},{"indexed":false,"internalType":"bool","name":"assertResolverSelector_","type":"bool"}],"name":"SetJobConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"preDefinedCalldata","type":"bytes"}],"name":"SetJobPreDefinedCalldata","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":false,"internalType":"address","name":"resolverAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"resolverCalldata","type":"bytes"}],"name":"SetJobResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keeperId","type":"uint256"},{"indexed":true,"internalType":"address","name":"prev","type":"address"},{"indexed":true,"internalType":"address","name":"worker","type":"address"}],"name":"SetWorkerAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keeperId","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"currentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pendingAmount","type":"uint256"}],"name":"Slash","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keeperId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"staker","type":"address"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"keeperId","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawCompensation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawJobCredits","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"jobOwner","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawJobOwnerCredits","type":"event"},{"inputs":[],"name":"CVP","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"}],"name":"acceptJobTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rewardPct_","type":"uint256"},{"internalType":"uint256","name":"fixedReward_","type":"uint256"},{"internalType":"uint256","name":"blockBaseFee_","type":"uint256"},{"internalType":"uint256","name":"gasUsed_","type":"uint256"}],"name":"calculateCompensationPure","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"}],"name":"depositJobCredits","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"for_","type":"address"}],"name":"depositJobOwnerCredits","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"execute_44g58pv","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperId_","type":"uint256"},{"internalType":"address","name":"to_","type":"address"}],"name":"finalizeRedeem","outputs":[{"internalType":"uint256","name":"redeemedCvp","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"internalType":"uint256","name":"minKeeperCvp_","type":"uint256"},{"internalType":"uint256","name":"pendingWithdrawalTimeoutSeconds_","type":"uint256"},{"internalType":"uint256","name":"feeTotal_","type":"uint256"},{"internalType":"uint256","name":"feePpm_","type":"uint256"},{"internalType":"uint256","name":"lastKeeperId_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"}],"name":"getJob","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"pendingTransfer","type":"address"},{"internalType":"uint256","name":"jobLevelMinKeeperCvp","type":"uint256"},{"components":[{"internalType":"uint8","name":"config","type":"uint8"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"uint88","name":"credits","type":"uint88"},{"internalType":"uint16","name":"maxBaseFeeGwei","type":"uint16"},{"internalType":"uint16","name":"rewardPct","type":"uint16"},{"internalType":"uint32","name":"fixedReward","type":"uint32"},{"internalType":"uint8","name":"calldataSource","type":"uint8"},{"internalType":"uint24","name":"intervalSeconds","type":"uint24"},{"internalType":"uint32","name":"lastExecutionAt","type":"uint32"}],"internalType":"struct IPPAgentV2Viewer.Job","name":"details","type":"tuple"},{"internalType":"bytes","name":"preDefinedCalldata","type":"bytes"},{"components":[{"internalType":"address","name":"resolverAddress","type":"address"},{"internalType":"bytes","name":"resolverCalldata","type":"bytes"}],"internalType":"struct IPPAgentV2Viewer.Resolver","name":"resolver","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"jobAddress_","type":"address"},{"internalType":"uint256","name":"jobId_","type":"uint256"}],"name":"getJobKey","outputs":[{"internalType":"bytes32","name":"jobKey","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"}],"name":"getJobRaw","outputs":[{"internalType":"uint256","name":"rawJob","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperId_","type":"uint256"}],"name":"getKeeper","outputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"worker","type":"address"},{"internalType":"uint256","name":"currentStake","type":"uint256"},{"internalType":"uint256","name":"slashedStake","type":"uint256"},{"internalType":"uint256","name":"compensation","type":"uint256"},{"internalType":"uint256","name":"pendingWithdrawalAmount","type":"uint256"},{"internalType":"uint256","name":"pendingWithdrawalEndAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperId_","type":"uint256"}],"name":"getKeeperWorkerAndStake","outputs":[{"internalType":"address","name":"worker","type":"address"},{"internalType":"uint256","name":"currentStake","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"},{"internalType":"address","name":"to_","type":"address"}],"name":"initiateJobTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"initiateRedeem","outputs":[{"internalType":"uint256","name":"pendingWithdrawalAfter","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"jobLastIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"jobOwnerCredits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"worker_","type":"address"},{"internalType":"uint256","name":"initialDepositAmount_","type":"uint256"}],"name":"registerAsKeeper","outputs":[{"internalType":"uint256","name":"keeperId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"jobAddress","type":"address"},{"internalType":"bytes4","name":"jobSelector","type":"bytes4"},{"internalType":"bool","name":"useJobOwnerCredits","type":"bool"},{"internalType":"bool","name":"assertResolverSelector","type":"bool"},{"internalType":"uint16","name":"maxBaseFeeGwei","type":"uint16"},{"internalType":"uint16","name":"rewardPct","type":"uint16"},{"internalType":"uint32","name":"fixedReward","type":"uint32"},{"internalType":"uint256","name":"jobMinCvp","type":"uint256"},{"internalType":"uint8","name":"calldataSource","type":"uint8"},{"internalType":"uint24","name":"intervalSeconds","type":"uint24"}],"internalType":"struct PPAgentV2.RegisterJobParams","name":"params_","type":"tuple"},{"components":[{"internalType":"address","name":"resolverAddress","type":"address"},{"internalType":"bytes","name":"resolverCalldata","type":"bytes"}],"internalType":"struct IPPAgentV2Viewer.Resolver","name":"resolver_","type":"tuple"},{"internalType":"bytes","name":"preDefinedCalldata_","type":"bytes"}],"name":"registerJob","outputs":[{"internalType":"bytes32","name":"jobKey","type":"bytes32"},{"internalType":"uint256","name":"jobId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minKeeperCvp_","type":"uint256"},{"internalType":"uint256","name":"timeoutSeconds_","type":"uint256"},{"internalType":"uint256","name":"feePpm_","type":"uint256"}],"name":"setAgentParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"},{"internalType":"bool","name":"isActive_","type":"bool"},{"internalType":"bool","name":"useJobOwnerCredits_","type":"bool"},{"internalType":"bool","name":"assertResolverSelector_","type":"bool"}],"name":"setJobConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"},{"internalType":"bytes","name":"preDefinedCalldata_","type":"bytes"}],"name":"setJobPreDefinedCalldata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"},{"components":[{"internalType":"address","name":"resolverAddress","type":"address"},{"internalType":"bytes","name":"resolverCalldata","type":"bytes"}],"internalType":"struct IPPAgentV2Viewer.Resolver","name":"resolver_","type":"tuple"}],"name":"setJobResolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperId_","type":"uint256"},{"internalType":"address","name":"worker_","type":"address"}],"name":"setWorkerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperId_","type":"uint256"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"currentAmount_","type":"uint256"},{"internalType":"uint256","name":"pendingAmount_","type":"uint256"}],"name":"slash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"},{"internalType":"uint16","name":"maxBaseFeeGwei_","type":"uint16"},{"internalType":"uint16","name":"rewardPct_","type":"uint16"},{"internalType":"uint32","name":"fixedReward_","type":"uint32"},{"internalType":"uint256","name":"jobMinCvp_","type":"uint256"},{"internalType":"uint24","name":"intervalSeconds_","type":"uint24"}],"name":"updateJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"keeperId_","type":"uint256"},{"internalType":"address payable","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawCompensation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"to_","type":"address"}],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"jobKey_","type":"bytes32"},{"internalType":"address payable","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawJobCredits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawJobOwnerCredits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"workerKeeperIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b5060405162004a9938038062004a998339810160408190526200003491620000d8565b6200003f336200006b565b60018290556001600160a01b038316608052600281905562000061846200006b565b5050505062000120565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620000d357600080fd5b919050565b60008060008060808587031215620000ef57600080fd5b620000fa85620000bb565b93506200010a60208601620000bb565b6040860151606090960151949790965092505050565b608051614941620001586000396000818161052301528181611c0d01528181611fb00152818161245b015261315201526149416000f3fe60806040526004361061024a5760003560e01c80638f245cc511610138578063c44a7130116100b0578063f729cf0d1161007f578063f8f6318811610064578063f8f63188146107fc578063fa713f40146108a9578063ffa1ad74146108d657600080fd5b8063f729cf0d14610792578063f83c1700146107c457600080fd5b8063c44a713014610644578063d217a89514610732578063efcdd7aa14610752578063f2fde38b1461077257600080fd5b80639da867d511610107578063b882eda6116100ec578063b882eda6146105c5578063c1484807146105d8578063c3f909d41461060057600080fd5b80639da867d514610585578063a34f8e14146105a557600080fd5b80638f245cc5146104f15780639230f2c0146105115780639af83df0146105455780639caec1d81461056557600080fd5b806329956b22116101cb578063572d417b1161019a578063715018a61161017f578063715018a6146104705780637b0472f0146104855780638da5cb5b146104a557600080fd5b8063572d417b146104305780636b5dd8551461045057600080fd5b806329956b22146103a35780633a1b9942146103c357806346e89169146103e3578063499925561461041057600080fd5b8063164e68de116102225780631c1ad03d116102075780631c1ad03d14610329578063293ac1bf14610356578063298a16131461037657600080fd5b8063164e68de146102cc57806317d11280146102ec57600080fd5b801561024f57806304d0fbdf146102665780630c4a06d014610299578063146cc168146102ac575b600080fd5b34801561025b57600080fd5b5061026461092c565b005b34801561027257600080fd5b50610286610281366004613a3e565b61116c565b6040519081526020015b60405180910390f35b6102646102a7366004613a6a565b6112b4565b3480156102b857600080fd5b506102646102c7366004613a83565b611323565b3480156102d857600080fd5b506102646102e7366004613aaf565b6113f9565b3480156102f857600080fd5b50610286610307366004613ad3565b600066038d7ea4c6800084026064619c40840185028702040195945050505050565b34801561033557600080fd5b50610286610344366004613aaf565b60146020526000908152604090205481565b34801561036257600080fd5b50610286610371366004613b05565b6114a4565b34801561038257600080fd5b50610286610391366004613aaf565b600c6020526000908152604090205481565b3480156103af57600080fd5b506102646103be366004613b27565b61167a565b3480156103cf57600080fd5b506102646103de366004613b98565b611796565b3480156103ef57600080fd5b506102866103fe366004613a6a565b60009081526006602052604090205490565b34801561041c57600080fd5b5061028661042b366004613bfe565b611b13565b34801561043c57600080fd5b5061026461044b366004613c77565b611cd2565b34801561045c57600080fd5b5061026461046b366004613cdc565b611cf6565b34801561047c57600080fd5b50610264611da6565b34801561049157600080fd5b506102646104a0366004613b05565b611dba565b3480156104b157600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610290565b3480156104fd57600080fd5b5061026461050c366004613d47565b611dd1565b34801561051d57600080fd5b506104cc7f000000000000000000000000000000000000000000000000000000000000000081565b34801561055157600080fd5b50610264610560366004613bfe565b611def565b34801561057157600080fd5b50610264610580366004613d8e565b611e77565b34801561059157600080fd5b506102646105a0366004613bfe565b612078565b3480156105b157600080fd5b506102646105c0366004613b27565b61212c565b6102646105d3366004613aaf565b6122bf565b6105eb6105e6366004613dcb565b6122d0565b60408051928352602083019190915201610290565b34801561060c57600080fd5b50600154600254600354600454600554604080519586526020860194909452928401919091526060830152608082015260a001610290565b34801561065057600080fd5b506106e561065f366004613a6a565b6000908152600e6020908152604080832054600d835281842054600f845282852054601085528386205460118652848720546012909652939095205473ffffffffffffffffffffffffffffffffffffffff9283169692821695740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff1694919392565b6040805173ffffffffffffffffffffffffffffffffffffffff9889168152979096166020880152948601939093526060850191909152608084015260a083015260c082015260e001610290565b34801561073e57600080fd5b5061026461074d366004613a3e565b612a1e565b34801561075e57600080fd5b5061026461076d366004613a6a565b612b25565b34801561077e57600080fd5b5061026461078d366004613aaf565b612bfb565b34801561079e57600080fd5b506107b26107ad366004613a6a565b612caf565b60405161029096959493929190613ef8565b3480156107d057600080fd5b506102866107df366004613a3e565b60008260601b6000528160e81b6014526017600020905092915050565b34801561080857600080fd5b5061087d610817366004613a6a565b6000908152600d602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169290910182905291565b6040805173ffffffffffffffffffffffffffffffffffffffff9093168352602083019190915201610290565b3480156108b557600080fd5b506102866108c4366004613aaf565b60136020526000908152604090205481565b3480156108e257600080fd5b5061091f6040518060400160405280600581526020017f322e322e3000000000000000000000000000000000000000000000000000000081525081565b6040516102909190614010565b60005a9050600060178060046000376000908120601c3560e81c808352600d602090815260409384902084518086019095525473ffffffffffffffffffffffffffffffffffffffff8116808652740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169185019190915291935060043560601c929091601b3560f81c919033146109f3576040517f4e2c6c2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015481602001516bffffffffffffffffffffffff161015610a41576040517fa42f03de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060008481526006602052604090205460018116610a93576040517f2cd4cf48000000000000000000000000000000000000000000000000000000008152600481018690526024015b60405180910390fd5b6008811615158015610ae65750600085815260086020908152604080832054868452600d909252909120547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16105b15610b1d576040517f6bb3355200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62ffffff60c882901c168015610b895760e082901c8015610b875780820142811115610b85576040517fe096085e0000000000000000000000000000000000000000000000000000000081526004810183905260248101849052426044820152606401610a8a565b505b505b50633b9aca0061ffff608083901c16024881108015610ba9575060018316155b15610be9576040517f725450b300000000000000000000000000000000000000000000000000000000815248600482015260248101829052604401610a8a565b333214610c22576040517fa397a6e500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061c3505a610c339190614052565b9050600060ff60c086901c166002811115610c5057610c50614065565b90506000816002811115610c6657610c66614065565b03610d4057604080517fffffffff0000000000000000000000000000000000000000000000000000000060d888901b16602082018190529173ffffffffffffffffffffffffffffffffffffffff8b1691859101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610cf191614094565b60006040518083038160008787f1925050503d8060008114610d2f576040519150601f19603f3d011682016040523d82523d6000602084013e610d34565b606091505b50508094505050610ec9565b6001816002811115610d5457610d54614065565b03610ddf578773ffffffffffffffffffffffffffffffffffffffff1682600760008c8152602001908152602001600020604051610d9191906140fd565b60006040518083038160008787f1925050503d8060008114610dcf576040519150601f19603f3d011682016040523d82523d6000602084013e610dd4565b606091505b505080935050610ec9565b6002816002811115610df357610df3614065565b03610e975736601f60405181831015610e2e577f47a0bafb000000000000000000000000000000000000000000000000000000008152600481fd5b8183039250828101604052828282376004881615610e83578760081c60e01b601f3560e01c60e01b14610e83577f84fb8275000000000000000000000000000000000000000000000000000000008152600481fd5b600080848360008f8af19550505050610ec9565b6040517fe49b9c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82156111185760008981526006602052604081205495505a8b03905060004880871015610ef35750855b66038d7ea4c6800063ffffffff60a08a901c16026064619c408501830261ffff60908c901c160204019150506000610f2d88600216151590565b15610f4157610f3c8c8361300c565b610fcb565b6affffffffffffffffffffff602889901c1682811015610f97576040517f208118ad0000000000000000000000000000000000000000000000000000000081526004810182905260248101849052604401610a8a565b82900360281b7fffffffffffffffffffffffffffffffff0000000000000000000000ffffffffff9890981697909717965060015b6002891615610ffd5760008a81526010602052604081208054849290610ff2908490614191565b9091555061102c9050565b604051339083156108fc029084906000818181858888f1935050505015801561102a573d6000803e3d6000fd5b505b62ffffff60c889901c16801561108a577bffffffffffffffffffffffffffffffffffffffffffffffffffffffff989098167fffffffff000000000000000000000000000000000000000000000000000000004260e01b161797600191505b5080156110a35760008c81526006602052604090208890555b50604080518a81526020810184905248818301523a60608201526080810183905260a08101899052905173ffffffffffffffffffffffffffffffffffffffff8c16918d917f59200007defbdd8d2c9e53dd05f81091fe977b424f38f2562df9ee8725d584699181900360c00190a35050611160565b3d6000819003611154576040517f81953a7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051816000823e8181fd5b50505050505050505050565b6000611177836130ba565b6001548210156111b3576040517f5945ea5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005600081546111c2906141a4565b91829055506000818152600e6020908152604080832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016339081179091558151808301835273ffffffffffffffffffffffffffffffffffffffff898116808352828601878152888852600d8752858820935190516bffffffffffffffffffffffff167401000000000000000000000000000000000000000002921691909117909155808552601490935281842085905590519394509092909184917f28e52185bb539dddafff5a07d4d7a65b6d44c6be0460f18b77ad1b5d7c7b6d7d9190a46112ae8183613117565b92915050565b6112bc61329b565b60008181526009602052604090205473ffffffffffffffffffffffffffffffffffffffff16611317576040517fa614bda700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611320816132d5565b50565b61132b6133ec565b62278d00821115611368576040517fde2180ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61c3508111156113a4576040517ff6f3292b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018390556002829055600481905560408051848152602081018490529081018290527f0c9773495c97952f53e7c7c23fc4ac36bc8d0e5c9ff4b5ffc8edd7b000931ea29060600160405180910390a1505050565b6114016133ec565b60038054600091829055604051909173ffffffffffffffffffffffffffffffffffffffff84169183156108fc0291849190818181858888f1935050505015801561144f573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff167f9bba815921f12cb7b1408e14b5ade745234397d39623ae5e7c82d693cb45815f8260405161149891815260200190565b60405180910390a25050565b60006114af8361343d565b6114b88261349a565b6000838152600d6020908152604080832054600f909252822054740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16916115048284614191565b90508185101561154a576040517f85348f7c0000000000000000000000000000000000000000000000000000000081526004810186905260248101839052604401610a8a565b80851115611595576040517fb3a6f108000000000000000000000000000000000000000000000000000000008152600481018690526024810184905260448101839052606401610a8a565b6000868152600f60209081526040808320839055600d8252808320805473ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000878b03808a036bffffffffffffffffffffffff16919091029190911790915560119092529091208054820190556002546116189042614191565b600088815260126020908152604091829020839055815189815290810184905290810185905290955087907f2f344f62e88371893ede3b3ea3af1bbba704965ff1a7acc83ce2e367dcc4720d9060600160405180910390a25050505092915050565b60008381526010602052604090205460018201611695578091505b61169e8261349a565b6116a7846134d4565b808211156116eb576040517fa20926670000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610a8a565b60008481526010602052604080822084840390555173ffffffffffffffffffffffffffffffffffffffff85169184156108fc02918591818181858888f1935050505015801561173e573d6000803e3d6000fd5b508273ffffffffffffffffffffffffffffffffffffffff16847f540b25d0ce24763795ee97abcbde8b65caecb84c08851dc1e31b5616deb86fb78460405161178891815260200190565b60405180910390a350505050565b61179f86613563565b6117b88561ffff168463ffffffff168661ffff166135c0565b600086815260066020908152604091829020825161012081018452905460ff808216835261010080830460e090811b7fffffffff0000000000000000000000000000000000000000000000000000000016958501959095526501000000000083046affffffffffffffffffffff1695840195909552700100000000000000000000000000000000820461ffff90811660608501527201000000000000000000000000000000000000830416608084015274010000000000000000000000000000000000000000820463ffffffff90811660a08501527801000000000000000000000000000000000000000000000000830490911660c08401819052790100000000000000000000000000000000000000000000000000830462ffffff908116958501959095527c010000000000000000000000000000000000000000000000000000000090920416938201939093529161192591841690600281111561192057611920614065565b61363d565b805160ff16831580159061193b57508151600816155b15611944576008175b831580156119555750815160081615155b1561195e576008185b600088815260066020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff8716178155600883529381902088905591815282547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000061ffff8c81169182027fffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffff16929092177201000000000000000000000000000000000000928c16928302177fffffffff000000ff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8c169081027fffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffff169190911779010000000000000000000000000000000000000000000000000062ffffff8b16908102919091179096558451918252928101919091529182015260608101869052608081019190915288907f36530212a24c816d4e494215a8c9e70aa89ee2c827cdaa6454c49a1b9c1f51709060a00160405180910390a25050505050505050565b6000611b1e8361343d565b600083815260126020526040902054421015611b66576040517fd364d89200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060008281526011602052604081205490819003611bb0576040517f9121b84f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526011602052604080822091909155517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015611c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7a91906141dc565b508173ffffffffffffffffffffffffffffffffffffffff16837f5e205b6e480b30b73f149f1e859cba98faf02d507680260f8626f19e640abdd283604051611cc491815260200190565b60405180910390a392915050565b611cdb83613563565b611ce68360016136ae565b611cf1838383613747565b505050565b611cff84613563565b60008315611d0b576001175b8215611d15576002175b8115611d1f576004175b600085815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016821790819055604080518615158152851515602082015284151581830152905187917f654d2f54a1effa88d8b821bb9edce7ee03d265c6796c42b5fe8b7d5d55fa48c8919081900360600190a2505050505050565b611dae6137a0565b611db86000613821565b565b611dc38161349a565b611dcd8282613117565b5050565b611dda82613563565b611de58260026136ae565b611dcd8282613896565b611df882613563565b6000828152600b602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917f40b48a3ccb089339d160145168f44ff509c18d032508f53097f0dc6b829065a691a45050565b611e7f6133ec565b6000611e8b8284614191565b9050611e968161349a565b8215611f3a576000858152600d602052604090208054849190601490611ee39084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff166141f9565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082600f60008781526020019081526020016000206000828254611f349190614191565b90915550505b8115611f645760008581526011602052604081208054849290611f5e908490614052565b90915550505b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015611ff9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201d91906141dc565b50604080518481526020810184905273ffffffffffffffffffffffffffffffffffffffff86169187917fa0a4bc88df8261867a0171209f23c36f265d479f8d378e57eaddd804fa5a6d4c910160405180910390a35050505050565b6120818261343d565b61208a816130ba565b6000828152600d60208181526040808420805473ffffffffffffffffffffffffffffffffffffffff908116808752601485528387208790559087168087528387208990558887529490935280547fffffffffffffffffffffffff00000000000000000000000000000000000000001684179055519092839186917f803f1e6c69bc471f5a71c877bbb0b42287843a87118166f8b4a6701e75a9ae6a91a4505050565b6000838152600660205260409020546501000000000090046affffffffffffffffffffff166001820161216a57806affffffffffffffffffffff1691505b61217384613563565b61217c8261349a565b81816affffffffffffffffffffff1610156121c3576040517f3166cb3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526006602052604080822080547fffffffffffffffffffffffffffffffff0000000000000000000000ffffffffff16650100000000008686036affffffffffffffffffffff16021790555173ffffffffffffffffffffffffffffffffffffffff8516916108fc851502918591818181858888f19350505050158015612250573d6000803e3d6000fd5b508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16857f50ee63b3e6b23156354ac5126b37abf7adccada099df4c9c70205f887d76e8ca856040516122b191815260200190565b60405180910390a450505050565b6122c761329b565b6113208161395a565b600080600c816122e36020890189613aaf565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002054612315906001614191565b905062ffffff811115612354576040517f3965512700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6affffffffffffffffffffff341115612399576040517f279f9e9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006123a86020880188613aaf565b73ffffffffffffffffffffffffffffffffffffffff16036123f5576040517f717833df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600261240961012088016101008901614236565b60ff161115612444576040517fe49b9c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166124886020880188613aaf565b73ffffffffffffffffffffffffffffffffffffffff16036124d5576040517f798943b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125156124ea61014088016101208901614251565b62ffffff1661250161012089016101008a01614236565b60ff16600281111561192057611920614065565b61255b61252860a088016080890161426c565b61ffff1661253c60e0890160c08a01614287565b63ffffffff1661255260c08a0160a08b0161426c565b61ffff166135c0565b61258261256b6020880188613aaf565b60601b600090815260e883901b6014526017902090565b9150806125926020880188613aaf565b73ffffffffffffffffffffffffffffffffffffffff16837fb9b4668f2492830c54dc2fa7c8e28d9184882690fbedea4abeb03f016663d212338a6040516125da9291906142d2565b60405180910390a460016125f661012088016101008901614236565b60ff16600281111561260a5761260a614065565b600281111561261b5761261b614065565b036126305761262b828585613747565b612678565b600261264461012088016101008901614236565b60ff16600281111561265857612658614065565b600281111561266957612669614065565b03612678576126788286613896565b6000600161268e61012089016101008a01614236565b60ff1660028111156126a2576126a2614065565b60028111156126b3576126b3614065565b146126cb576126c86040880160208901614412565b90505b60016126dd6060890160408a0161442d565b156126e6576002175b6126f66080890160608a0161442d565b156126ff576004175b60e08801351561270d576008175b604080516101208101825260ff831681527fffffffff00000000000000000000000000000000000000000000000000000000841660208201526000918101919091526060810161276360a08b0160808c0161426c565b61ffff16815260200161277c60c08b0160a08c0161426c565b61ffff16815260200161279560e08b0160c08c01614287565b63ffffffff1681526020016127b26101208b016101008c01614236565b60ff1681526020016127cc6101408b016101208c01614251565b62ffffff168152602001600063ffffffff168152506006600086815260200190815260200160002060008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548163ffffffff021916908360e01c021790555060408201518160000160056101000a8154816affffffffffffffffffffff02191690836affffffffffffffffffffff16021790555060608201518160000160106101000a81548161ffff021916908361ffff16021790555060808201518160000160126101000a81548161ffff021916908361ffff16021790555060a08201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160000160186101000a81548160ff021916908360ff16021790555060e08201518160000160196101000a81548162ffffff021916908362ffffff16021790555061010082015181600001601c6101000a81548163ffffffff021916908363ffffffff1602179055509050508760e001356008600086815260200190815260200160002081905550505080600c60008860000160208101906129829190613aaf565b73ffffffffffffffffffffffffffffffffffffffff16815260208082019290925260409081016000908120939093558483526009909152902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790553415612a15576129f9606087016040880161442d565b15612a0c57612a073361395a565b612a15565b612a15826132d5565b94509492505050565b3360009081526013602052604090205460018201612a3a578091505b612a438261349a565b81811015612a7d576040517f3166cb3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526013602052604080822084840390555173ffffffffffffffffffffffffffffffffffffffff85169184156108fc02918591818181858888f19350505050158015612ad1573d6000803e3d6000fd5b5060405182815273ffffffffffffffffffffffffffffffffffffffff84169033907f307ba9008c2eb2a77892b84866e728ce368061fe4e72e27221a4f63dfe50c085906020015b60405180910390a3505050565b6000818152600b602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612b82576040517ff097464000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526009602090815260408083208054337fffffffffffffffffffffffff00000000000000000000000000000000000000009182168117909255600b909352818420805490931690925551909183917f1f436fd25d350ec220955f7c1fadbae0d1e695cf8135a25ef9c0eab577223b9f9190a350565b612c036137a0565b73ffffffffffffffffffffffffffffffffffffffff8116612ca6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a8a565b61132081613821565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905281908190604080518082019091526000815260606020820181905290600087815260096020908152604080832054600b83528184205460088452828520546006855283862060078652848720600a875296859020855161012081018752915460ff808216845261010080830460e090811b7fffffffff00000000000000000000000000000000000000000000000000000000169a86019a909a526501000000000083046affffffffffffffffffffff1698850198909852700100000000000000000000000000000000820461ffff90811660608601527201000000000000000000000000000000000000830416608085015274010000000000000000000000000000000000000000820463ffffffff90811660a08601527801000000000000000000000000000000000000000000000000830490911660c0850152790100000000000000000000000000000000000000000000000000820462ffffff16988401989098527c0100000000000000000000000000000000000000000000000000000000900490961694810194909452855473ffffffffffffffffffffffffffffffffffffffff938416969390921694909392918290612eb4906140b0565b80601f0160208091040260200160405190810160405280929190818152602001828054612ee0906140b0565b8015612f2d5780601f10612f0257610100808354040283529160200191612f2d565b820191906000526020600020905b815481529060010190602001808311612f1057829003601f168201915b505060408051808201909152855473ffffffffffffffffffffffffffffffffffffffff1681526001860180549597509094869450602086019350909150612f73906140b0565b80601f0160208091040260200160405190810160405280929190818152602001828054612f9f906140b0565b8015612fec5780601f10612fc157610100808354040283529160200191612fec565b820191906000526020600020905b815481529060010190602001808311612fcf57829003601f168201915b505050505081525050905095509550955095509550955091939550919395565b60008281526009602090815260408083205473ffffffffffffffffffffffffffffffffffffffff168352601390915290205481811015613082576040517f5a27597b0000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610a8a565b60009283526009602090815260408085205473ffffffffffffffffffffffffffffffffffffffff168552601390915290922091039055565b73ffffffffffffffffffffffffffffffffffffffff811660009081526014602052604090205415611320576040517f81f9afb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af11580156131b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d491906141dc565b506000828152600d60205260409020805482919060149061321c9084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1661444a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550817fb1ab6be18e00655e8a052f6565edf39309c0038d15c0be04c4f2beadbb65f924823360405161149892919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b34600003611db8576040517f50e620e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806132e06139db565b600085815260066020526040812054929450909250906133179083906501000000000090046affffffffffffffffffffff16614191565b90506affffffffffffffffffffff81111561335e576040517f279f9e9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380548401905560008481526006602090815260409182902080547fffffffffffffffffffffffffffffffff0000000000000000000000ffffffffff16650100000000006affffffffffffffffffffff8616021790558151848152908101859052339186917fcde4bbac54ccbe285df37dd4861ba498967f700c80555187ce308b499d8980f89101611788565b60005473ffffffffffffffffffffffffffffffffffffffff163314611db8576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600e602052604090205473ffffffffffffffffffffffffffffffffffffffff163314611320576040517fd6b3e94e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003611320576040517f06551f4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600e602052604090205473ffffffffffffffffffffffffffffffffffffffff16331480159061352c57506000818152600d602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b15611320576040517f3377c89900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526009602052604090205473ffffffffffffffffffffffffffffffffffffffff163314611320576040517fddf69e8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036135fa576040517f2f61889e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81158015613606575080155b15611cf1576040517f896ce9f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b811580156136775750600081600281111561365a5761365a614065565b14806136775750600181600281111561367557613675614065565b145b15611dcd576040517f732dc01400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060028111156136c0576136c0614065565b6000838152600660205260409020547801000000000000000000000000000000000000000000000000900460ff1660028111156136ff576136ff614065565b600281111561371057613710614065565b14611dcd576040517fcaa30c5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602052604090206137608284836144ec565b50827fd22231b382b21cb9521ddd32d9acb2f6ee7720c09de2cfba0fbadabd15932a948383604051613793929190614650565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611db8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a8a565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006138a56020830183613aaf565b73ffffffffffffffffffffffffffffffffffffffff16036138f2576040517fa7220e5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600a60205260409020819061390c82826146c9565b508290507f259cf3286fb257c644397539ce6a98f9c054f66d90577d69e02503a85a5e99ce61393e6020840184613aaf565b61394b6020850185614664565b60405161149893929190614880565b6000806139656139db565b600380548301905573ffffffffffffffffffffffffffffffffffffffff8516600081815260136020526040908190208054840190555192945090925033917f37d2d0ab5d3d834b49345443201eb89ca4ac72dc66ca316e761fd1bb3d667d1d90612b189085908790918252602082015260400190565b600080620f4240600454346139f091906148b9565b6139fa91906148d0565b9150613a068234614052565b90509091565b73ffffffffffffffffffffffffffffffffffffffff8116811461132057600080fd5b8035613a3981613a0c565b919050565b60008060408385031215613a5157600080fd5b8235613a5c81613a0c565b946020939093013593505050565b600060208284031215613a7c57600080fd5b5035919050565b600080600060608486031215613a9857600080fd5b505081359360208301359350604090920135919050565b600060208284031215613ac157600080fd5b8135613acc81613a0c565b9392505050565b60008060008060808587031215613ae957600080fd5b5050823594602084013594506040840135936060013592509050565b60008060408385031215613b1857600080fd5b50508035926020909101359150565b600080600060608486031215613b3c57600080fd5b833592506020840135613b4e81613a0c565b929592945050506040919091013590565b803561ffff81168114613a3957600080fd5b803563ffffffff81168114613a3957600080fd5b803562ffffff81168114613a3957600080fd5b60008060008060008060c08789031215613bb157600080fd5b86359550613bc160208801613b5f565b9450613bcf60408801613b5f565b9350613bdd60608801613b71565b925060808701359150613bf260a08801613b85565b90509295509295509295565b60008060408385031215613c1157600080fd5b823591506020830135613c2381613a0c565b809150509250929050565b60008083601f840112613c4057600080fd5b50813567ffffffffffffffff811115613c5857600080fd5b602083019150836020828501011115613c7057600080fd5b9250929050565b600080600060408486031215613c8c57600080fd5b83359250602084013567ffffffffffffffff811115613caa57600080fd5b613cb686828701613c2e565b9497909650939450505050565b801515811461132057600080fd5b8035613a3981613cc3565b60008060008060808587031215613cf257600080fd5b843593506020850135613d0481613cc3565b92506040850135613d1481613cc3565b91506060850135613d2481613cc3565b939692955090935050565b600060408284031215613d4157600080fd5b50919050565b60008060408385031215613d5a57600080fd5b82359150602083013567ffffffffffffffff811115613d7857600080fd5b613d8485828601613d2f565b9150509250929050565b60008060008060808587031215613da457600080fd5b843593506020850135613db681613a0c565b93969395505050506040820135916060013590565b600080600080848603610180811215613de357600080fd5b61014080821215613df357600080fd5b869550850135905067ffffffffffffffff80821115613e1157600080fd5b613e1d88838901613d2f565b9450610160870135915080821115613e3457600080fd5b50613e4187828801613c2e565b95989497509550505050565b60005b83811015613e68578181015183820152602001613e50565b50506000910152565b60008151808452613e89816020860160208601613e4d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff81511682526000602082015160406020850152613ef06040850182613e71565b949350505050565b60006101c073ffffffffffffffffffffffffffffffffffffffff808a16845280891660208501525086604084015260ff86511660608401527fffffffff0000000000000000000000000000000000000000000000000000000060208701511660808401526040860151613f7a60a08501826affffffffffffffffffffff169052565b50606086015161ffff90811660c085015260808701511660e084015260a086015163ffffffff81166101008086019190915260c088015160ff1661012086015260e088015162ffffff1661014086015287015163ffffffff16610160850152506101808301819052613fee81840186613e71565b90508281036101a08401526140038185613ebb565b9998505050505050505050565b602081526000613acc6020830184613e71565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156112ae576112ae614023565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600082516140a6818460208701613e4d565b9190910192915050565b600181811c908216806140c457607f821691505b602082108103613d41577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600080835461410b816140b0565b60018281168015614123576001811461415657614185565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450614185565b8760005260208060002060005b8581101561417c5781548a820152908401908201614163565b50505082870194505b50929695505050505050565b808201808211156112ae576112ae614023565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036141d5576141d5614023565b5060010190565b6000602082840312156141ee57600080fd5b8151613acc81613cc3565b6bffffffffffffffffffffffff82811682821603908082111561421e5761421e614023565b5092915050565b803560ff81168114613a3957600080fd5b60006020828403121561424857600080fd5b613acc82614225565b60006020828403121561426357600080fd5b613acc82613b85565b60006020828403121561427e57600080fd5b613acc82613b5f565b60006020828403121561429957600080fd5b613acc82613b71565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114613a3957600080fd5b73ffffffffffffffffffffffffffffffffffffffff83168152610160810161431a6020830161430085613a2e565b73ffffffffffffffffffffffffffffffffffffffff169052565b614326602084016142a2565b7fffffffff00000000000000000000000000000000000000000000000000000000811660408401525061435b60408401613cd1565b80151560608401525061437060608401613cd1565b80151560808401525061438560808401613b5f565b61ffff811660a08401525061439c60a08401613b5f565b61ffff811660c0840152506143b360c08401613b71565b63ffffffff811660e08401525061010060e0840135818401526143d7818501614225565b90506101206143ea8185018360ff169052565b6143f5818601613b85565b91505061440a61014084018262ffffff169052565b509392505050565b60006020828403121561442457600080fd5b613acc826142a2565b60006020828403121561443f57600080fd5b8135613acc81613cc3565b6bffffffffffffffffffffffff81811683821601908082111561421e5761421e614023565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f821115611cf157600081815260208120601f850160051c810160208610156144c55750805b601f850160051c820191505b818110156144e4578281556001016144d1565b505050505050565b67ffffffffffffffff8311156145045761450461446f565b6145188361451283546140b0565b8361449e565b6000601f84116001811461456a57600085156145345750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614600565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156145b95786850135825560209485019460019092019101614599565b50868210156145f4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000613ef0602083018486614607565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261469957600080fd5b83018035915067ffffffffffffffff8211156146b457600080fd5b602001915036819003821315613c7057600080fd5b81356146d481613a0c565b73ffffffffffffffffffffffffffffffffffffffff81167fffffffffffffffffffffffff00000000000000000000000000000000000000008354161782555060018082016020808501357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe186360301811261474e57600080fd5b8501803567ffffffffffffffff81111561476757600080fd5b803603838301131561477857600080fd5b61478c8161478686546140b0565b8661449e565b6000601f8211600181146147e057600083156147aa57508382018501355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178655614875565b6000868152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841690835b8281101561482e5786850188013582559387019390890190870161480f565b508482101561486b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88660031b161c198785880101351681555b50508683881b0186555b505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082015260006148b0604083018486614607565b95945050505050565b80820281158282048414176112ae576112ae614023565b600082614906577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea26469706673582212202f00e773eb3ece6ace307971e0278b49b0ef5cb356a963d590a3af39eeb3d1cb64736f6c63430008110033000000000000000000000000b258302c3f209491d604165549079680708581cc00000000000000000000000038e4adb44ef08f22f5b5b76a8f0c2d0dcbe7dca100000000000000000000000000000000000000000000003635c9adc5dea000000000000000000000000000000000000000000000000000000000000000069780

Deployed Bytecode

0x60806040526004361061024a5760003560e01c80638f245cc511610138578063c44a7130116100b0578063f729cf0d1161007f578063f8f6318811610064578063f8f63188146107fc578063fa713f40146108a9578063ffa1ad74146108d657600080fd5b8063f729cf0d14610792578063f83c1700146107c457600080fd5b8063c44a713014610644578063d217a89514610732578063efcdd7aa14610752578063f2fde38b1461077257600080fd5b80639da867d511610107578063b882eda6116100ec578063b882eda6146105c5578063c1484807146105d8578063c3f909d41461060057600080fd5b80639da867d514610585578063a34f8e14146105a557600080fd5b80638f245cc5146104f15780639230f2c0146105115780639af83df0146105455780639caec1d81461056557600080fd5b806329956b22116101cb578063572d417b1161019a578063715018a61161017f578063715018a6146104705780637b0472f0146104855780638da5cb5b146104a557600080fd5b8063572d417b146104305780636b5dd8551461045057600080fd5b806329956b22146103a35780633a1b9942146103c357806346e89169146103e3578063499925561461041057600080fd5b8063164e68de116102225780631c1ad03d116102075780631c1ad03d14610329578063293ac1bf14610356578063298a16131461037657600080fd5b8063164e68de146102cc57806317d11280146102ec57600080fd5b801561024f57806304d0fbdf146102665780630c4a06d014610299578063146cc168146102ac575b600080fd5b34801561025b57600080fd5b5061026461092c565b005b34801561027257600080fd5b50610286610281366004613a3e565b61116c565b6040519081526020015b60405180910390f35b6102646102a7366004613a6a565b6112b4565b3480156102b857600080fd5b506102646102c7366004613a83565b611323565b3480156102d857600080fd5b506102646102e7366004613aaf565b6113f9565b3480156102f857600080fd5b50610286610307366004613ad3565b600066038d7ea4c6800084026064619c40840185028702040195945050505050565b34801561033557600080fd5b50610286610344366004613aaf565b60146020526000908152604090205481565b34801561036257600080fd5b50610286610371366004613b05565b6114a4565b34801561038257600080fd5b50610286610391366004613aaf565b600c6020526000908152604090205481565b3480156103af57600080fd5b506102646103be366004613b27565b61167a565b3480156103cf57600080fd5b506102646103de366004613b98565b611796565b3480156103ef57600080fd5b506102866103fe366004613a6a565b60009081526006602052604090205490565b34801561041c57600080fd5b5061028661042b366004613bfe565b611b13565b34801561043c57600080fd5b5061026461044b366004613c77565b611cd2565b34801561045c57600080fd5b5061026461046b366004613cdc565b611cf6565b34801561047c57600080fd5b50610264611da6565b34801561049157600080fd5b506102646104a0366004613b05565b611dba565b3480156104b157600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610290565b3480156104fd57600080fd5b5061026461050c366004613d47565b611dd1565b34801561051d57600080fd5b506104cc7f00000000000000000000000038e4adb44ef08f22f5b5b76a8f0c2d0dcbe7dca181565b34801561055157600080fd5b50610264610560366004613bfe565b611def565b34801561057157600080fd5b50610264610580366004613d8e565b611e77565b34801561059157600080fd5b506102646105a0366004613bfe565b612078565b3480156105b157600080fd5b506102646105c0366004613b27565b61212c565b6102646105d3366004613aaf565b6122bf565b6105eb6105e6366004613dcb565b6122d0565b60408051928352602083019190915201610290565b34801561060c57600080fd5b50600154600254600354600454600554604080519586526020860194909452928401919091526060830152608082015260a001610290565b34801561065057600080fd5b506106e561065f366004613a6a565b6000908152600e6020908152604080832054600d835281842054600f845282852054601085528386205460118652848720546012909652939095205473ffffffffffffffffffffffffffffffffffffffff9283169692821695740100000000000000000000000000000000000000009092046bffffffffffffffffffffffff1694919392565b6040805173ffffffffffffffffffffffffffffffffffffffff9889168152979096166020880152948601939093526060850191909152608084015260a083015260c082015260e001610290565b34801561073e57600080fd5b5061026461074d366004613a3e565b612a1e565b34801561075e57600080fd5b5061026461076d366004613a6a565b612b25565b34801561077e57600080fd5b5061026461078d366004613aaf565b612bfb565b34801561079e57600080fd5b506107b26107ad366004613a6a565b612caf565b60405161029096959493929190613ef8565b3480156107d057600080fd5b506102866107df366004613a3e565b60008260601b6000528160e81b6014526017600020905092915050565b34801561080857600080fd5b5061087d610817366004613a6a565b6000908152600d602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169290910182905291565b6040805173ffffffffffffffffffffffffffffffffffffffff9093168352602083019190915201610290565b3480156108b557600080fd5b506102866108c4366004613aaf565b60136020526000908152604090205481565b3480156108e257600080fd5b5061091f6040518060400160405280600581526020017f322e322e3000000000000000000000000000000000000000000000000000000081525081565b6040516102909190614010565b60005a9050600060178060046000376000908120601c3560e81c808352600d602090815260409384902084518086019095525473ffffffffffffffffffffffffffffffffffffffff8116808652740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169185019190915291935060043560601c929091601b3560f81c919033146109f3576040517f4e2c6c2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015481602001516bffffffffffffffffffffffff161015610a41576040517fa42f03de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060008481526006602052604090205460018116610a93576040517f2cd4cf48000000000000000000000000000000000000000000000000000000008152600481018690526024015b60405180910390fd5b6008811615158015610ae65750600085815260086020908152604080832054868452600d909252909120547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16105b15610b1d576040517f6bb3355200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62ffffff60c882901c168015610b895760e082901c8015610b875780820142811115610b85576040517fe096085e0000000000000000000000000000000000000000000000000000000081526004810183905260248101849052426044820152606401610a8a565b505b505b50633b9aca0061ffff608083901c16024881108015610ba9575060018316155b15610be9576040517f725450b300000000000000000000000000000000000000000000000000000000815248600482015260248101829052604401610a8a565b333214610c22576040517fa397a6e500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061c3505a610c339190614052565b9050600060ff60c086901c166002811115610c5057610c50614065565b90506000816002811115610c6657610c66614065565b03610d4057604080517fffffffff0000000000000000000000000000000000000000000000000000000060d888901b16602082018190529173ffffffffffffffffffffffffffffffffffffffff8b1691859101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610cf191614094565b60006040518083038160008787f1925050503d8060008114610d2f576040519150601f19603f3d011682016040523d82523d6000602084013e610d34565b606091505b50508094505050610ec9565b6001816002811115610d5457610d54614065565b03610ddf578773ffffffffffffffffffffffffffffffffffffffff1682600760008c8152602001908152602001600020604051610d9191906140fd565b60006040518083038160008787f1925050503d8060008114610dcf576040519150601f19603f3d011682016040523d82523d6000602084013e610dd4565b606091505b505080935050610ec9565b6002816002811115610df357610df3614065565b03610e975736601f60405181831015610e2e577f47a0bafb000000000000000000000000000000000000000000000000000000008152600481fd5b8183039250828101604052828282376004881615610e83578760081c60e01b601f3560e01c60e01b14610e83577f84fb8275000000000000000000000000000000000000000000000000000000008152600481fd5b600080848360008f8af19550505050610ec9565b6040517fe49b9c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82156111185760008981526006602052604081205495505a8b03905060004880871015610ef35750855b66038d7ea4c6800063ffffffff60a08a901c16026064619c408501830261ffff60908c901c160204019150506000610f2d88600216151590565b15610f4157610f3c8c8361300c565b610fcb565b6affffffffffffffffffffff602889901c1682811015610f97576040517f208118ad0000000000000000000000000000000000000000000000000000000081526004810182905260248101849052604401610a8a565b82900360281b7fffffffffffffffffffffffffffffffff0000000000000000000000ffffffffff9890981697909717965060015b6002891615610ffd5760008a81526010602052604081208054849290610ff2908490614191565b9091555061102c9050565b604051339083156108fc029084906000818181858888f1935050505015801561102a573d6000803e3d6000fd5b505b62ffffff60c889901c16801561108a577bffffffffffffffffffffffffffffffffffffffffffffffffffffffff989098167fffffffff000000000000000000000000000000000000000000000000000000004260e01b161797600191505b5080156110a35760008c81526006602052604090208890555b50604080518a81526020810184905248818301523a60608201526080810183905260a08101899052905173ffffffffffffffffffffffffffffffffffffffff8c16918d917f59200007defbdd8d2c9e53dd05f81091fe977b424f38f2562df9ee8725d584699181900360c00190a35050611160565b3d6000819003611154576040517f81953a7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051816000823e8181fd5b50505050505050505050565b6000611177836130ba565b6001548210156111b3576040517f5945ea5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005600081546111c2906141a4565b91829055506000818152600e6020908152604080832080547fffffffffffffffffffffffff000000000000000000000000000000000000000016339081179091558151808301835273ffffffffffffffffffffffffffffffffffffffff898116808352828601878152888852600d8752858820935190516bffffffffffffffffffffffff167401000000000000000000000000000000000000000002921691909117909155808552601490935281842085905590519394509092909184917f28e52185bb539dddafff5a07d4d7a65b6d44c6be0460f18b77ad1b5d7c7b6d7d9190a46112ae8183613117565b92915050565b6112bc61329b565b60008181526009602052604090205473ffffffffffffffffffffffffffffffffffffffff16611317576040517fa614bda700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611320816132d5565b50565b61132b6133ec565b62278d00821115611368576040517fde2180ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61c3508111156113a4576040517ff6f3292b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018390556002829055600481905560408051848152602081018490529081018290527f0c9773495c97952f53e7c7c23fc4ac36bc8d0e5c9ff4b5ffc8edd7b000931ea29060600160405180910390a1505050565b6114016133ec565b60038054600091829055604051909173ffffffffffffffffffffffffffffffffffffffff84169183156108fc0291849190818181858888f1935050505015801561144f573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff167f9bba815921f12cb7b1408e14b5ade745234397d39623ae5e7c82d693cb45815f8260405161149891815260200190565b60405180910390a25050565b60006114af8361343d565b6114b88261349a565b6000838152600d6020908152604080832054600f909252822054740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16916115048284614191565b90508185101561154a576040517f85348f7c0000000000000000000000000000000000000000000000000000000081526004810186905260248101839052604401610a8a565b80851115611595576040517fb3a6f108000000000000000000000000000000000000000000000000000000008152600481018690526024810184905260448101839052606401610a8a565b6000868152600f60209081526040808320839055600d8252808320805473ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000878b03808a036bffffffffffffffffffffffff16919091029190911790915560119092529091208054820190556002546116189042614191565b600088815260126020908152604091829020839055815189815290810184905290810185905290955087907f2f344f62e88371893ede3b3ea3af1bbba704965ff1a7acc83ce2e367dcc4720d9060600160405180910390a25050505092915050565b60008381526010602052604090205460018201611695578091505b61169e8261349a565b6116a7846134d4565b808211156116eb576040517fa20926670000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610a8a565b60008481526010602052604080822084840390555173ffffffffffffffffffffffffffffffffffffffff85169184156108fc02918591818181858888f1935050505015801561173e573d6000803e3d6000fd5b508273ffffffffffffffffffffffffffffffffffffffff16847f540b25d0ce24763795ee97abcbde8b65caecb84c08851dc1e31b5616deb86fb78460405161178891815260200190565b60405180910390a350505050565b61179f86613563565b6117b88561ffff168463ffffffff168661ffff166135c0565b600086815260066020908152604091829020825161012081018452905460ff808216835261010080830460e090811b7fffffffff0000000000000000000000000000000000000000000000000000000016958501959095526501000000000083046affffffffffffffffffffff1695840195909552700100000000000000000000000000000000820461ffff90811660608501527201000000000000000000000000000000000000830416608084015274010000000000000000000000000000000000000000820463ffffffff90811660a08501527801000000000000000000000000000000000000000000000000830490911660c08401819052790100000000000000000000000000000000000000000000000000830462ffffff908116958501959095527c010000000000000000000000000000000000000000000000000000000090920416938201939093529161192591841690600281111561192057611920614065565b61363d565b805160ff16831580159061193b57508151600816155b15611944576008175b831580156119555750815160081615155b1561195e576008185b600088815260066020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff8716178155600883529381902088905591815282547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000061ffff8c81169182027fffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffff16929092177201000000000000000000000000000000000000928c16928302177fffffffff000000ff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8c169081027fffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffff169190911779010000000000000000000000000000000000000000000000000062ffffff8b16908102919091179096558451918252928101919091529182015260608101869052608081019190915288907f36530212a24c816d4e494215a8c9e70aa89ee2c827cdaa6454c49a1b9c1f51709060a00160405180910390a25050505050505050565b6000611b1e8361343d565b600083815260126020526040902054421015611b66576040517fd364d89200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060008281526011602052604081205490819003611bb0576040517f9121b84f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526011602052604080822091909155517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f00000000000000000000000038e4adb44ef08f22f5b5b76a8f0c2d0dcbe7dca1169063a9059cbb906044016020604051808303816000875af1158015611c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7a91906141dc565b508173ffffffffffffffffffffffffffffffffffffffff16837f5e205b6e480b30b73f149f1e859cba98faf02d507680260f8626f19e640abdd283604051611cc491815260200190565b60405180910390a392915050565b611cdb83613563565b611ce68360016136ae565b611cf1838383613747565b505050565b611cff84613563565b60008315611d0b576001175b8215611d15576002175b8115611d1f576004175b600085815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016821790819055604080518615158152851515602082015284151581830152905187917f654d2f54a1effa88d8b821bb9edce7ee03d265c6796c42b5fe8b7d5d55fa48c8919081900360600190a2505050505050565b611dae6137a0565b611db86000613821565b565b611dc38161349a565b611dcd8282613117565b5050565b611dda82613563565b611de58260026136ae565b611dcd8282613896565b611df882613563565b6000828152600b602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917f40b48a3ccb089339d160145168f44ff509c18d032508f53097f0dc6b829065a691a45050565b611e7f6133ec565b6000611e8b8284614191565b9050611e968161349a565b8215611f3a576000858152600d602052604090208054849190601490611ee39084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff166141f9565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082600f60008781526020019081526020016000206000828254611f349190614191565b90915550505b8115611f645760008581526011602052604081208054849290611f5e908490614052565b90915550505b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018390527f00000000000000000000000038e4adb44ef08f22f5b5b76a8f0c2d0dcbe7dca1169063a9059cbb906044016020604051808303816000875af1158015611ff9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201d91906141dc565b50604080518481526020810184905273ffffffffffffffffffffffffffffffffffffffff86169187917fa0a4bc88df8261867a0171209f23c36f265d479f8d378e57eaddd804fa5a6d4c910160405180910390a35050505050565b6120818261343d565b61208a816130ba565b6000828152600d60208181526040808420805473ffffffffffffffffffffffffffffffffffffffff908116808752601485528387208790559087168087528387208990558887529490935280547fffffffffffffffffffffffff00000000000000000000000000000000000000001684179055519092839186917f803f1e6c69bc471f5a71c877bbb0b42287843a87118166f8b4a6701e75a9ae6a91a4505050565b6000838152600660205260409020546501000000000090046affffffffffffffffffffff166001820161216a57806affffffffffffffffffffff1691505b61217384613563565b61217c8261349a565b81816affffffffffffffffffffff1610156121c3576040517f3166cb3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526006602052604080822080547fffffffffffffffffffffffffffffffff0000000000000000000000ffffffffff16650100000000008686036affffffffffffffffffffff16021790555173ffffffffffffffffffffffffffffffffffffffff8516916108fc851502918591818181858888f19350505050158015612250573d6000803e3d6000fd5b508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16857f50ee63b3e6b23156354ac5126b37abf7adccada099df4c9c70205f887d76e8ca856040516122b191815260200190565b60405180910390a450505050565b6122c761329b565b6113208161395a565b600080600c816122e36020890189613aaf565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002054612315906001614191565b905062ffffff811115612354576040517f3965512700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6affffffffffffffffffffff341115612399576040517f279f9e9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006123a86020880188613aaf565b73ffffffffffffffffffffffffffffffffffffffff16036123f5576040517f717833df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600261240961012088016101008901614236565b60ff161115612444576040517fe49b9c9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000038e4adb44ef08f22f5b5b76a8f0c2d0dcbe7dca1166124886020880188613aaf565b73ffffffffffffffffffffffffffffffffffffffff16036124d5576040517f798943b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125156124ea61014088016101208901614251565b62ffffff1661250161012089016101008a01614236565b60ff16600281111561192057611920614065565b61255b61252860a088016080890161426c565b61ffff1661253c60e0890160c08a01614287565b63ffffffff1661255260c08a0160a08b0161426c565b61ffff166135c0565b61258261256b6020880188613aaf565b60601b600090815260e883901b6014526017902090565b9150806125926020880188613aaf565b73ffffffffffffffffffffffffffffffffffffffff16837fb9b4668f2492830c54dc2fa7c8e28d9184882690fbedea4abeb03f016663d212338a6040516125da9291906142d2565b60405180910390a460016125f661012088016101008901614236565b60ff16600281111561260a5761260a614065565b600281111561261b5761261b614065565b036126305761262b828585613747565b612678565b600261264461012088016101008901614236565b60ff16600281111561265857612658614065565b600281111561266957612669614065565b03612678576126788286613896565b6000600161268e61012089016101008a01614236565b60ff1660028111156126a2576126a2614065565b60028111156126b3576126b3614065565b146126cb576126c86040880160208901614412565b90505b60016126dd6060890160408a0161442d565b156126e6576002175b6126f66080890160608a0161442d565b156126ff576004175b60e08801351561270d576008175b604080516101208101825260ff831681527fffffffff00000000000000000000000000000000000000000000000000000000841660208201526000918101919091526060810161276360a08b0160808c0161426c565b61ffff16815260200161277c60c08b0160a08c0161426c565b61ffff16815260200161279560e08b0160c08c01614287565b63ffffffff1681526020016127b26101208b016101008c01614236565b60ff1681526020016127cc6101408b016101208c01614251565b62ffffff168152602001600063ffffffff168152506006600086815260200190815260200160002060008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548163ffffffff021916908360e01c021790555060408201518160000160056101000a8154816affffffffffffffffffffff02191690836affffffffffffffffffffff16021790555060608201518160000160106101000a81548161ffff021916908361ffff16021790555060808201518160000160126101000a81548161ffff021916908361ffff16021790555060a08201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160000160186101000a81548160ff021916908360ff16021790555060e08201518160000160196101000a81548162ffffff021916908362ffffff16021790555061010082015181600001601c6101000a81548163ffffffff021916908363ffffffff1602179055509050508760e001356008600086815260200190815260200160002081905550505080600c60008860000160208101906129829190613aaf565b73ffffffffffffffffffffffffffffffffffffffff16815260208082019290925260409081016000908120939093558483526009909152902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790553415612a15576129f9606087016040880161442d565b15612a0c57612a073361395a565b612a15565b612a15826132d5565b94509492505050565b3360009081526013602052604090205460018201612a3a578091505b612a438261349a565b81811015612a7d576040517f3166cb3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526013602052604080822084840390555173ffffffffffffffffffffffffffffffffffffffff85169184156108fc02918591818181858888f19350505050158015612ad1573d6000803e3d6000fd5b5060405182815273ffffffffffffffffffffffffffffffffffffffff84169033907f307ba9008c2eb2a77892b84866e728ce368061fe4e72e27221a4f63dfe50c085906020015b60405180910390a3505050565b6000818152600b602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612b82576040517ff097464000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526009602090815260408083208054337fffffffffffffffffffffffff00000000000000000000000000000000000000009182168117909255600b909352818420805490931690925551909183917f1f436fd25d350ec220955f7c1fadbae0d1e695cf8135a25ef9c0eab577223b9f9190a350565b612c036137a0565b73ffffffffffffffffffffffffffffffffffffffff8116612ca6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a8a565b61132081613821565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905281908190604080518082019091526000815260606020820181905290600087815260096020908152604080832054600b83528184205460088452828520546006855283862060078652848720600a875296859020855161012081018752915460ff808216845261010080830460e090811b7fffffffff00000000000000000000000000000000000000000000000000000000169a86019a909a526501000000000083046affffffffffffffffffffff1698850198909852700100000000000000000000000000000000820461ffff90811660608601527201000000000000000000000000000000000000830416608085015274010000000000000000000000000000000000000000820463ffffffff90811660a08601527801000000000000000000000000000000000000000000000000830490911660c0850152790100000000000000000000000000000000000000000000000000820462ffffff16988401989098527c0100000000000000000000000000000000000000000000000000000000900490961694810194909452855473ffffffffffffffffffffffffffffffffffffffff938416969390921694909392918290612eb4906140b0565b80601f0160208091040260200160405190810160405280929190818152602001828054612ee0906140b0565b8015612f2d5780601f10612f0257610100808354040283529160200191612f2d565b820191906000526020600020905b815481529060010190602001808311612f1057829003601f168201915b505060408051808201909152855473ffffffffffffffffffffffffffffffffffffffff1681526001860180549597509094869450602086019350909150612f73906140b0565b80601f0160208091040260200160405190810160405280929190818152602001828054612f9f906140b0565b8015612fec5780601f10612fc157610100808354040283529160200191612fec565b820191906000526020600020905b815481529060010190602001808311612fcf57829003601f168201915b505050505081525050905095509550955095509550955091939550919395565b60008281526009602090815260408083205473ffffffffffffffffffffffffffffffffffffffff168352601390915290205481811015613082576040517f5a27597b0000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610a8a565b60009283526009602090815260408085205473ffffffffffffffffffffffffffffffffffffffff168552601390915290922091039055565b73ffffffffffffffffffffffffffffffffffffffff811660009081526014602052604090205415611320576040517f81f9afb300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f00000000000000000000000038e4adb44ef08f22f5b5b76a8f0c2d0dcbe7dca173ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af11580156131b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131d491906141dc565b506000828152600d60205260409020805482919060149061321c9084907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1661444a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550817fb1ab6be18e00655e8a052f6565edf39309c0038d15c0be04c4f2beadbb65f924823360405161149892919091825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b34600003611db8576040517f50e620e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806132e06139db565b600085815260066020526040812054929450909250906133179083906501000000000090046affffffffffffffffffffff16614191565b90506affffffffffffffffffffff81111561335e576040517f279f9e9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380548401905560008481526006602090815260409182902080547fffffffffffffffffffffffffffffffff0000000000000000000000ffffffffff16650100000000006affffffffffffffffffffff8616021790558151848152908101859052339186917fcde4bbac54ccbe285df37dd4861ba498967f700c80555187ce308b499d8980f89101611788565b60005473ffffffffffffffffffffffffffffffffffffffff163314611db8576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600e602052604090205473ffffffffffffffffffffffffffffffffffffffff163314611320576040517fd6b3e94e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003611320576040517f06551f4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600e602052604090205473ffffffffffffffffffffffffffffffffffffffff16331480159061352c57506000818152600d602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b15611320576040517f3377c89900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526009602052604090205473ffffffffffffffffffffffffffffffffffffffff163314611320576040517fddf69e8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826000036135fa576040517f2f61889e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81158015613606575080155b15611cf1576040517f896ce9f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b811580156136775750600081600281111561365a5761365a614065565b14806136775750600181600281111561367557613675614065565b145b15611dcd576040517f732dc01400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060028111156136c0576136c0614065565b6000838152600660205260409020547801000000000000000000000000000000000000000000000000900460ff1660028111156136ff576136ff614065565b600281111561371057613710614065565b14611dcd576040517fcaa30c5b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602052604090206137608284836144ec565b50827fd22231b382b21cb9521ddd32d9acb2f6ee7720c09de2cfba0fbadabd15932a948383604051613793929190614650565b60405180910390a2505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611db8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a8a565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006138a56020830183613aaf565b73ffffffffffffffffffffffffffffffffffffffff16036138f2576040517fa7220e5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600a60205260409020819061390c82826146c9565b508290507f259cf3286fb257c644397539ce6a98f9c054f66d90577d69e02503a85a5e99ce61393e6020840184613aaf565b61394b6020850185614664565b60405161149893929190614880565b6000806139656139db565b600380548301905573ffffffffffffffffffffffffffffffffffffffff8516600081815260136020526040908190208054840190555192945090925033917f37d2d0ab5d3d834b49345443201eb89ca4ac72dc66ca316e761fd1bb3d667d1d90612b189085908790918252602082015260400190565b600080620f4240600454346139f091906148b9565b6139fa91906148d0565b9150613a068234614052565b90509091565b73ffffffffffffffffffffffffffffffffffffffff8116811461132057600080fd5b8035613a3981613a0c565b919050565b60008060408385031215613a5157600080fd5b8235613a5c81613a0c565b946020939093013593505050565b600060208284031215613a7c57600080fd5b5035919050565b600080600060608486031215613a9857600080fd5b505081359360208301359350604090920135919050565b600060208284031215613ac157600080fd5b8135613acc81613a0c565b9392505050565b60008060008060808587031215613ae957600080fd5b5050823594602084013594506040840135936060013592509050565b60008060408385031215613b1857600080fd5b50508035926020909101359150565b600080600060608486031215613b3c57600080fd5b833592506020840135613b4e81613a0c565b929592945050506040919091013590565b803561ffff81168114613a3957600080fd5b803563ffffffff81168114613a3957600080fd5b803562ffffff81168114613a3957600080fd5b60008060008060008060c08789031215613bb157600080fd5b86359550613bc160208801613b5f565b9450613bcf60408801613b5f565b9350613bdd60608801613b71565b925060808701359150613bf260a08801613b85565b90509295509295509295565b60008060408385031215613c1157600080fd5b823591506020830135613c2381613a0c565b809150509250929050565b60008083601f840112613c4057600080fd5b50813567ffffffffffffffff811115613c5857600080fd5b602083019150836020828501011115613c7057600080fd5b9250929050565b600080600060408486031215613c8c57600080fd5b83359250602084013567ffffffffffffffff811115613caa57600080fd5b613cb686828701613c2e565b9497909650939450505050565b801515811461132057600080fd5b8035613a3981613cc3565b60008060008060808587031215613cf257600080fd5b843593506020850135613d0481613cc3565b92506040850135613d1481613cc3565b91506060850135613d2481613cc3565b939692955090935050565b600060408284031215613d4157600080fd5b50919050565b60008060408385031215613d5a57600080fd5b82359150602083013567ffffffffffffffff811115613d7857600080fd5b613d8485828601613d2f565b9150509250929050565b60008060008060808587031215613da457600080fd5b843593506020850135613db681613a0c565b93969395505050506040820135916060013590565b600080600080848603610180811215613de357600080fd5b61014080821215613df357600080fd5b869550850135905067ffffffffffffffff80821115613e1157600080fd5b613e1d88838901613d2f565b9450610160870135915080821115613e3457600080fd5b50613e4187828801613c2e565b95989497509550505050565b60005b83811015613e68578181015183820152602001613e50565b50506000910152565b60008151808452613e89816020860160208601613e4d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff81511682526000602082015160406020850152613ef06040850182613e71565b949350505050565b60006101c073ffffffffffffffffffffffffffffffffffffffff808a16845280891660208501525086604084015260ff86511660608401527fffffffff0000000000000000000000000000000000000000000000000000000060208701511660808401526040860151613f7a60a08501826affffffffffffffffffffff169052565b50606086015161ffff90811660c085015260808701511660e084015260a086015163ffffffff81166101008086019190915260c088015160ff1661012086015260e088015162ffffff1661014086015287015163ffffffff16610160850152506101808301819052613fee81840186613e71565b90508281036101a08401526140038185613ebb565b9998505050505050505050565b602081526000613acc6020830184613e71565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156112ae576112ae614023565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600082516140a6818460208701613e4d565b9190910192915050565b600181811c908216806140c457607f821691505b602082108103613d41577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600080835461410b816140b0565b60018281168015614123576001811461415657614185565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450614185565b8760005260208060002060005b8581101561417c5781548a820152908401908201614163565b50505082870194505b50929695505050505050565b808201808211156112ae576112ae614023565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036141d5576141d5614023565b5060010190565b6000602082840312156141ee57600080fd5b8151613acc81613cc3565b6bffffffffffffffffffffffff82811682821603908082111561421e5761421e614023565b5092915050565b803560ff81168114613a3957600080fd5b60006020828403121561424857600080fd5b613acc82614225565b60006020828403121561426357600080fd5b613acc82613b85565b60006020828403121561427e57600080fd5b613acc82613b5f565b60006020828403121561429957600080fd5b613acc82613b71565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114613a3957600080fd5b73ffffffffffffffffffffffffffffffffffffffff83168152610160810161431a6020830161430085613a2e565b73ffffffffffffffffffffffffffffffffffffffff169052565b614326602084016142a2565b7fffffffff00000000000000000000000000000000000000000000000000000000811660408401525061435b60408401613cd1565b80151560608401525061437060608401613cd1565b80151560808401525061438560808401613b5f565b61ffff811660a08401525061439c60a08401613b5f565b61ffff811660c0840152506143b360c08401613b71565b63ffffffff811660e08401525061010060e0840135818401526143d7818501614225565b90506101206143ea8185018360ff169052565b6143f5818601613b85565b91505061440a61014084018262ffffff169052565b509392505050565b60006020828403121561442457600080fd5b613acc826142a2565b60006020828403121561443f57600080fd5b8135613acc81613cc3565b6bffffffffffffffffffffffff81811683821601908082111561421e5761421e614023565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f821115611cf157600081815260208120601f850160051c810160208610156144c55750805b601f850160051c820191505b818110156144e4578281556001016144d1565b505050505050565b67ffffffffffffffff8311156145045761450461446f565b6145188361451283546140b0565b8361449e565b6000601f84116001811461456a57600085156145345750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614600565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156145b95786850135825560209485019460019092019101614599565b50868210156145f4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000613ef0602083018486614607565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261469957600080fd5b83018035915067ffffffffffffffff8211156146b457600080fd5b602001915036819003821315613c7057600080fd5b81356146d481613a0c565b73ffffffffffffffffffffffffffffffffffffffff81167fffffffffffffffffffffffff00000000000000000000000000000000000000008354161782555060018082016020808501357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe186360301811261474e57600080fd5b8501803567ffffffffffffffff81111561476757600080fd5b803603838301131561477857600080fd5b61478c8161478686546140b0565b8661449e565b6000601f8211600181146147e057600083156147aa57508382018501355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178655614875565b6000868152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0841690835b8281101561482e5786850188013582559387019390890190870161480f565b508482101561486b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88660031b161c198785880101351681555b50508683881b0186555b505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff841681526040602082015260006148b0604083018486614607565b95945050505050565b80820281158282048414176112ae576112ae614023565b600082614906577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea26469706673582212202f00e773eb3ece6ace307971e0278b49b0ef5cb356a963d590a3af39eeb3d1cb64736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000b258302c3f209491d604165549079680708581cc00000000000000000000000038e4adb44ef08f22f5b5b76a8f0c2d0dcbe7dca100000000000000000000000000000000000000000000003635c9adc5dea000000000000000000000000000000000000000000000000000000000000000069780

-----Decoded View---------------
Arg [0] : owner_ (address): 0xB258302C3f209491d604165549079680708581Cc
Arg [1] : cvp_ (address): 0x38e4adB44ef08F22F5B5b76A8f0c2d0dCbE7DcA1
Arg [2] : minKeeperCvp_ (uint256): 1000000000000000000000
Arg [3] : pendingWithdrawalTimeoutSeconds_ (uint256): 432000

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000b258302c3f209491d604165549079680708581cc
Arg [1] : 00000000000000000000000038e4adb44ef08f22f5b5b76a8f0c2d0dcbe7dca1
Arg [2] : 00000000000000000000000000000000000000000000003635c9adc5dea00000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000069780


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.