// Sources flattened with hardhat v2.12.7 https://hardhat.org

// File src/v0.8/dev/automation/2_1/interfaces/ILogAutomation.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

struct Log {
  uint256 index;
  uint256 txIndex;
  bytes32 txHash;
  uint256 blockNumber;
  bytes32 blockHash;
  address source;
  bytes32[] topics;
  bytes data;
}

interface ILogAutomation {
  /**
   * @notice method that is simulated by the keepers to see if any work actually
   * needs to be performed. This method does does not actually need to be
   * executable, and since it is only ever simulated it can consume lots of gas.
   * @dev To ensure that it is never called, you may want to add the
   * cannotExecute modifier from KeeperBase to your implementation of this
   * method.
   * @param log the raw log data matching the filter that this contract has
   * registered as a trigger
   * @param checkData user-specified extra data to provide context to this upkeep
   * @return upkeepNeeded boolean to indicate whether the keeper should call
   * performUpkeep or not.
   * @return performData bytes that the keeper should call performUpkeep with, if
   * upkeep is needed. If you would like to encode data to decode later, try
   * `abi.encode`.
   */
  function checkLog(
    Log calldata log,
    bytes memory checkData
  ) external returns (bool upkeepNeeded, bytes memory performData);

  /**
   * @notice method that is actually executed by the keepers, via the registry.
   * The data returned by the checkUpkeep simulation will be passed into
   * this method to actually be executed.
   * @dev The input to this method should not be trusted, and the caller of the
   * method should not even be restricted to any single registry. Anyone should
   * be able call it, and the input should be validated, there is no guarantee
   * that the data passed in is the performData returned from checkUpkeep. This
   * could happen due to malicious keepers, racing keepers, or simply a state
   * change while the performUpkeep transaction is waiting for confirmation.
   * Always validate the data passed in.
   * @param performData is the data which was passed back from the checkData
   * simulation. If it is encoded, it can easily be decoded into other types by
   * calling `abi.decode`. This data should not be trusted, and should be
   * validated against the contract's current state.
   */
  function performUpkeep(bytes calldata performData) external;
}


pragma solidity 0.8.18;

contract LogUpkeepCounter is ILogAutomation {
  bytes32 sig1 = 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d;
  bytes32 sig2 = 0x57b1de35764b0939dde00771c7069cdf8d6a65d6a175623f19aa18784fd4c6da;
  bytes32 sig3 = 0x1da9f70fe932e73fba9374396c5c0b02dbd170f951874b7b4afabe4dd029a9c8;
  bytes32 sig4 = 0x5121119bad45ca7e58e0bdadf39045f5111e93ba4304a0f6457a3e7bc9791e71;

  event PerformingUpkeep(
    address indexed from,
    uint256 initialBlock,
    uint256 lastBlock,
    uint256 previousBlock,
    uint256 counter
  );

  /**
   * @dev we include multiple event types for testing various filters, signatures, etc
   */
  event Trigger(); // 0x3d53a39550e04688065827f3bb86584cb007ab9ebca7ebd528e7301c9c31eb5d
  event Trigger(uint256 a); // 0x57b1de35764b0939dde00771c7069cdf8d6a65d6a175623f19aa18784fd4c6da
  event Trigger(uint256 a, uint256 b); // 0x1da9f70fe932e73fba9374396c5c0b02dbd170f951874b7b4afabe4dd029a9c8
  event Trigger(uint256 a, uint256 b, uint256 c); // 0x5121119bad45ca7e58e0bdadf39045f5111e93ba4304a0f6457a3e7bc9791e71

  uint256 public lastBlock;
  uint256 public previousPerformBlock;
  uint256 public initialBlock;
  uint256 public counter;

      address private _owner;
  modifier onlyOwner() {
  require(owner() == msg.sender, "Ownership Assertion: Caller of the function is not the owner.");
  _;
  }
  function owner() public view virtual returns (address) {
    return _owner;
  }

  constructor() {
    _owner = msg.sender;
    previousPerformBlock = 0;
    lastBlock = block.number;
    initialBlock = 0;
    counter = 0;
  }

  function start() public onlyOwner {
    // need an initial event to begin the cycle
    emit Trigger();
    emit Trigger(1);
    emit Trigger(1, 2);
    emit Trigger(1, 2, 3);
  }

  function checkLog(Log calldata log, bytes memory) external view override returns (bool, bytes memory) {
    if (log.topics[0] == sig1 || log.topics[0] == sig2 || log.topics[0] == sig3 || log.topics[0] == sig4) {
      return (true, abi.encode(log));
    } else {
      revert("could not find matching event sig");
    }
  }

  function performUpkeep(bytes calldata performData) external override {
    if (initialBlock == 0) {
      initialBlock = block.number;
    }
    lastBlock = block.number;
    counter = counter + 1;
    previousPerformBlock = lastBlock;
    Log memory log = abi.decode(performData, (Log));
    if (log.topics[0] == sig1) {
      emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter);
    } else if (log.topics[0] == sig2) {
      emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter);
    } else if (log.topics[0] == sig3) {
      emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter);
    } else if (log.topics[0] == sig4) {
      emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter);
    } else {
      revert("could not find matching sig");
    }
  }

  function reset() external onlyOwner {
    initialBlock = 0;
    counter = 0;
  }
}