// File: @chainlink/contracts/src/v0.8/AutomationBase.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract AutomationBase {
  error OnlySimulatedBackend();

  /**
   * @notice method that allows it to be simulated via eth_call by checking that
   * the sender is the zero address.
   */
  function preventExecution() internal view {
    if (tx.origin != address(0)) {
      revert OnlySimulatedBackend();
    }
  }

  /**
   * @notice modifier that allows it to be simulated via eth_call by checking
   * that the sender is the zero address.
   */
  modifier cannotExecute() {
    preventExecution();
    _;
  }
}

// File: @chainlink/contracts/src/v0.8/AutomationCompatible.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./AutomationBase.sol";
import "./interfaces/AutomationCompatibleInterface.sol";

abstract contract AutomationCompatible is AutomationBase, AutomationCompatibleInterface {}

// File: @chainlink/contracts/src/v0.8/interfaces/AutomationCompatibleInterface.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface AutomationCompatibleInterface {
  /**
   * @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 checkData specified in the upkeep registration so it is always the
   * same for a registered upkeep. This can easily be broken down into specific
   * arguments using `abi.decode`, so multiple upkeeps can be registered on the
   * same contract and easily differentiated by the contract.
   * @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 checkUpkeep(bytes calldata 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;
}

// File: contracts/@chainlink/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IFunctionsRouter} from "./interfaces/IFunctionsRouter.sol";
import {IFunctionsClient} from "./interfaces/IFunctionsClient.sol";

import {FunctionsRequest} from "./libraries/FunctionsRequest.sol";

// @title The Chainlink Functions client contract
// @notice Contract developers can inherit this contract in order to make Chainlink Functions requests
abstract contract FunctionsClient is IFunctionsClient {
  using FunctionsRequest for FunctionsRequest.Request;

  IFunctionsRouter internal immutable i_router;

  event RequestSent(bytes32 indexed id);
  event RequestFulfilled(bytes32 indexed id);

  error OnlyRouterCanFulfill();

  constructor(address router) {
    i_router = IFunctionsRouter(router);
  }

  // @notice Sends a Chainlink Functions request
  // @param data The CBOR encoded bytes data for a Functions request
  // @param subscriptionId The subscription ID that will be charged to service the request
  // @param callbackGasLimit the amount of gas that will be available for the fulfillment callback
  // @return requestId The generated request ID for this request
  function _sendRequest(
    bytes memory data,
    uint64 subscriptionId,
    uint32 callbackGasLimit,
    bytes32 donId
  ) internal returns (bytes32) {
    bytes32 requestId = i_router.sendRequest(
      subscriptionId,
      data,
      FunctionsRequest.REQUEST_DATA_VERSION,
      callbackGasLimit,
      donId
    );
    emit RequestSent(requestId);
    return requestId;
  }

  // @notice User defined function to handle a response from the DON
  // @param requestId The request ID, returned by sendRequest()
  // @param response Aggregated response from the execution of the user's source code
  // @param err Aggregated error from the execution of the user code or from the execution pipeline
  // @dev Either response or error parameter will be set, but never both
  function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal virtual;

  // @inheritdoc IFunctionsClient
  function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external override {
    if (msg.sender != address(i_router)) {
      revert OnlyRouterCanFulfill();
    }
    fulfillRequest(requestId, response, err);
  }
}

// File: contracts/@chainlink/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsClient.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

// @title Chainlink Functions client interface.
interface IFunctionsClient {
  // @notice Chainlink Functions response handler called by the Functions Router
  // during fullilment from the designated transmitter node in an OCR round.
  // @param requestId The requestId returned by FunctionsClient.sendRequest().
  // @param response Aggregated response from the request's source code.
  // @param err Aggregated error either from the request's source code or from the execution pipeline.
  // @dev Either response or error parameter will be set, but never both.
  function handleOracleFulfillment(bytes32 requestId, bytes memory response, bytes memory err) external;
}

// File: contracts/@chainlink/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsRouter.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {FunctionsResponse} from "../libraries/FunctionsResponse.sol";

// @title Chainlink Functions Router interface.
interface IFunctionsRouter {
  // @notice The identifier of the route to retrieve the address of the access control contract
  // The access control contract controls which accounts can manage subscriptions
  // @return id - bytes32 id that can be passed to the "getContractById" of the Router
  function getAllowListId() external view returns (bytes32);

  // @notice Set the identifier of the route to retrieve the address of the access control contract
  // The access control contract controls which accounts can manage subscriptions
  function setAllowListId(bytes32 allowListId) external;

  // @notice Get the flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network
  // @return adminFee
  function getAdminFee() external view returns (uint72 adminFee);

  // @notice Sends a request using the provided subscriptionId
  // @param subscriptionId - A unique subscription ID allocated by billing system,
  // a client can make requests from different contracts referencing the same subscription
  // @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request
  // @param dataVersion - Gas limit for the fulfillment callback
  // @param callbackGasLimit - Gas limit for the fulfillment callback
  // @param donId - An identifier used to determine which route to send the request along
  // @return requestId - A unique request identifier
  function sendRequest(
    uint64 subscriptionId,
    bytes calldata data,
    uint16 dataVersion,
    uint32 callbackGasLimit,
    bytes32 donId
  ) external returns (bytes32);

  // @notice Sends a request to the proposed contracts
  // @param subscriptionId - A unique subscription ID allocated by billing system,
  // a client can make requests from different contracts referencing the same subscription
  // @param data - CBOR encoded Chainlink Functions request data, use FunctionsClient API to encode a request
  // @param dataVersion - Gas limit for the fulfillment callback
  // @param callbackGasLimit - Gas limit for the fulfillment callback
  // @param donId - An identifier used to determine which route to send the request along
  // @return requestId - A unique request identifier
  function sendRequestToProposed(
    uint64 subscriptionId,
    bytes calldata data,
    uint16 dataVersion,
    uint32 callbackGasLimit,
    bytes32 donId
  ) external returns (bytes32);

  // @notice Fulfill the request by:
  // - calling back the data that the Oracle returned to the client contract
  // - pay the DON for processing the request
  // @dev Only callable by the Coordinator contract that is saved in the commitment
  // @param response response data from DON consensus
  // @param err error from DON consensus
  // @param juelsPerGas - current rate of juels/gas
  // @param costWithoutFulfillment - The cost of processing the request (in Juels of LINK ), without fulfillment
  // @param transmitter - The Node that transmitted the OCR report
  // @param commitment - The parameters of the request that must be held consistent between request and response time
  // @return fulfillResult -
  // @return callbackGasCostJuels -
  function fulfill(
    bytes memory response,
    bytes memory err,
    uint96 juelsPerGas,
    uint96 costWithoutFulfillment,
    address transmitter,
    FunctionsResponse.Commitment memory commitment
  ) external returns (FunctionsResponse.FulfillResult, uint96);

  // @notice Validate requested gas limit is below the subscription max.
  // @param subscriptionId subscription ID
  // @param callbackGasLimit desired callback gas limit
  function isValidCallbackGasLimit(uint64 subscriptionId, uint32 callbackGasLimit) external view;

  // @notice Get the current contract given an ID
  // @param id A bytes32 identifier for the route
  // @return contract The current contract address
  function getContractById(bytes32 id) external view returns (address);

  // @notice Get the proposed next contract given an ID
  // @param id A bytes32 identifier for the route
  // @return contract The current or proposed contract address
  function getProposedContractById(bytes32 id) external view returns (address);

  // @notice Return the latest proprosal set
  // @return ids The identifiers of the contracts to update
  // @return to The addresses of the contracts that will be updated to
  function getProposedContractSet() external view returns (bytes32[] memory, address[] memory);

  // @notice Proposes one or more updates to the contract routes
  // @dev Only callable by owner
  function proposeContractsUpdate(bytes32[] memory proposalSetIds, address[] memory proposalSetAddresses) external;

  // @notice Updates the current contract routes to the proposed contracts
  // @dev Only callable by owner
  function updateContracts() external;

  // @dev Puts the system into an emergency stopped state.
  // @dev Only callable by owner
  function pause() external;

  // @dev Takes the system out of an emergency stopped state.
  // @dev Only callable by owner
  function unpause() external;
}

// File: contracts/@chainlink/contracts/src/v0.8/functions/dev/1_0_0/interfaces/IFunctionsSubscriptions.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {FunctionsResponse} from "../libraries/FunctionsResponse.sol";

// @title Chainlink Functions Subscription interface.
interface IFunctionsSubscriptions {
  struct Subscription {
    uint96 balance; // ═════════╗ Common LINK balance that is controlled by the Router to be used for all consumer requests.
    address owner; // ══════════╝ The owner can fund/withdraw/cancel the subscription.
    uint96 blockedBalance; // ══╗ LINK balance that is reserved to pay for pending consumer requests.
    address proposedOwner; // ══╝ For safely transferring sub ownership.
    address[] consumers; // ════╸ Client contracts that can use the subscription
    bytes32 flags; // ══════════╸ Per-subscription flags
  }

  struct Consumer {
    bool allowed; // ══════════════╗ Owner can fund/withdraw/cancel the sub.
    uint64 initiatedRequests; //   ║ The number of requests that have been started
    uint64 completedRequests; // ══╝ The number of requests that have successfully completed or timed out
  }

  // @notice Get details about a subscription.
  // @param subscriptionId - the ID of the subscription
  // @return subscription - see IFunctionsSubscriptions.Subscription for more information on the structure
  function getSubscription(uint64 subscriptionId) external view returns (Subscription memory);

  // @notice Get details about a consumer of a subscription.
  // @param client - the consumer contract address
  // @param subscriptionId - the ID of the subscription
  // @return consumer - see IFunctionsSubscriptions.Consumer for more information on the structure
  function getConsumer(address client, uint64 subscriptionId) external view returns (Consumer memory);

  // @notice Get details about the total amount of LINK within the system
  // @return totalBalance - total Juels of LINK held by the contract
  function getTotalBalance() external view returns (uint96);

  // @notice Get details about the total number of subscription accounts
  // @return count - total number of subscriptions in the system
  function getSubscriptionCount() external view returns (uint64);

  // @notice Time out all expired requests: unlocks funds and removes the ability for the request to be fulfilled
  // @param requestsToTimeoutByCommitment - A list of request commitments to time out
  // @dev The commitment can be found on the "OracleRequest" event created when sending the request.
  function timeoutRequests(FunctionsResponse.Commitment[] calldata requestsToTimeoutByCommitment) external;

  // @notice Oracle withdraw LINK earned through fulfilling requests
  // @notice If amount is 0 the full balance will be withdrawn
  // @notice Both signing and transmitting wallets will have a balance to withdraw
  // @param recipient where to send the funds
  // @param amount amount to withdraw
  function oracleWithdraw(address recipient, uint96 amount) external;

  // @notice Owner cancel subscription, sends remaining link directly to the subscription owner.
  // @dev Only callable by the Router Owner
  // @param subscriptionId subscription id
  // @dev notably can be called even if there are pending requests, outstanding ones may fail onchain
  function ownerCancelSubscription(uint64 subscriptionId) external;

  // @notice Recover link sent with transfer instead of transferAndCall.
  // @dev Only callable by the Router Owner
  // @param to address to send link to
  function recoverFunds(address to) external;

  // @notice Create a new subscription.
  // @return subscriptionId - A unique subscription id.
  // @dev You can manage the consumer set dynamically with addConsumer/removeConsumer.
  // @dev Note to fund the subscription, use transferAndCall. For example
  // @dev  LINKTOKEN.transferAndCall(
  // @dev    address(ROUTER),
  // @dev    amount,
  // @dev    abi.encode(subscriptionId));
  function createSubscription() external returns (uint64);

  // @notice Create a new subscription and add a consumer.
  // @return subscriptionId - A unique subscription id.
  // @dev You can manage the consumer set dynamically with addConsumer/removeConsumer.
  // @dev Note to fund the subscription, use transferAndCall. For example
  // @dev  LINKTOKEN.transferAndCall(
  // @dev    address(ROUTER),
  // @dev    amount,
  // @dev    abi.encode(subscriptionId));
  function createSubscriptionWithConsumer(address consumer) external returns (uint64 subscriptionId);

  // @notice Propose a new owner for a subscription.
  // @dev Only callable by the Subscription's owner
  // @param subscriptionId - ID of the subscription
  // @param newOwner - proposed new owner of the subscription
  function proposeSubscriptionOwnerTransfer(uint64 subscriptionId, address newOwner) external;

  // @notice Accept an ownership transfer.
  // @param subscriptionId - ID of the subscription
  // @dev will revert if original owner of subscriptionId has
  // not requested that msg.sender become the new owner.
  function acceptSubscriptionOwnerTransfer(uint64 subscriptionId) external;

  // @notice Remove a consumer from a Chainlink Functions subscription.
  // @dev Only callable by the Subscription's owner
  // @param subscriptionId - ID of the subscription
  // @param consumer - Consumer to remove from the subscription
  function removeConsumer(uint64 subscriptionId, address consumer) external;

  // @notice Add a consumer to a Chainlink Functions subscription.
  // @dev Only callable by the Subscription's owner
  // @param subscriptionId - ID of the subscription
  // @param consumer - New consumer which can use the subscription
  function addConsumer(uint64 subscriptionId, address consumer) external;

  // @notice Cancel a subscription
  // @dev Only callable by the Subscription's owner
  // @param subscriptionId - ID of the subscription
  // @param to - Where to send the remaining LINK to
  function cancelSubscription(uint64 subscriptionId, address to) external;

  // @notice Check to see if there exists a request commitment for all consumers for a given sub.
  // @param subscriptionId - ID of the subscription
  // @return true if there exists at least one unfulfilled request for the subscription, false
  // otherwise.
  // @dev Looping is bounded to MAX_CONSUMERS*(number of DONs).
  // @dev Used to disable subscription canceling while outstanding request are present.
  function pendingRequestExists(uint64 subscriptionId) external view returns (bool);

  // @notice Set subscription specific flags for a subscription.
  // Each byte of the flag is used to represent a resource tier that the subscription can utilize.
  // @param subscriptionId - ID of the subscription
  // @param flags - desired flag values
  function setFlags(uint64 subscriptionId, bytes32 flags) external;

  // @notice Get flags for a given subscription.
  // @param subscriptionId - ID of the subscription
  // @return flags - current flag values
  function getFlags(uint64 subscriptionId) external view returns (bytes32);
}

// File: contracts/@chainlink/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {CBOR} from "../../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol";

// @title Library for encoding the input data of a Functions request into CBOR
library FunctionsRequest {
  using CBOR for CBOR.CBORBuffer;

  uint16 public constant REQUEST_DATA_VERSION = 1;
  uint256 internal constant DEFAULT_BUFFER_SIZE = 256;

  enum Location {
    Inline, // Provided within the Request
    Remote, // Hosted through remote location that can be accessed through a provided URL
    DONHosted // Hosted on the DON's storage
  }

  enum CodeLanguage {
    JavaScript
    // In future version we may add other languages
  }

  struct Request {
    Location codeLocation; // ════════════╸ The location of the source code that will be executed on each node in the DON
    Location secretsLocation; // ═════════╸ The location of secrets that will be passed into the source code. *Only Remote secrets are supported
    CodeLanguage language; // ════════════╸ The coding language that the source code is written in
    string source; // ════════════════════╸ Raw source code for Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal number for Request.codeLocation of Location.DONHosted
    bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use addDONHostedSecrets())
    bytes requestSignature; // ═══════════╸ Signature generated by the subscription owner's EOA
    string[] args; // ════════════════════╸ String arguments that will be passed into the source code
    bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code
  }

  error EmptySource();
  error EmptySecrets();
  error EmptyArgs();
  error NoInlineSecrets();

  // @notice Encodes a Request to CBOR encoded bytes
  // @param self The request to encode
  // @return CBOR encoded bytes
  function encodeCBOR(Request memory self) internal pure returns (bytes memory) {
    CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);

    buffer.writeString("codeLocation");
    buffer.writeUInt256(uint256(self.codeLocation));

    buffer.writeString("language");
    buffer.writeUInt256(uint256(self.language));

    buffer.writeString("source");
    buffer.writeString(self.source);

    if (self.requestSignature.length > 0) {
      buffer.writeString("requestSignature");
      buffer.writeBytes(self.requestSignature);
    }

    if (self.args.length > 0) {
      buffer.writeString("args");
      buffer.startArray();
      for (uint256 i = 0; i < self.args.length; ++i) {
        buffer.writeString(self.args[i]);
      }
      buffer.endSequence();
    }

    if (self.encryptedSecretsReference.length > 0) {
      if (self.secretsLocation == Location.Inline) {
        revert NoInlineSecrets();
      }
      buffer.writeString("secretsLocation");
      buffer.writeUInt256(uint256(self.secretsLocation));
      buffer.writeString("secrets");
      buffer.writeBytes(self.encryptedSecretsReference);
    }

    if (self.bytesArgs.length > 0) {
      buffer.writeString("bytesArgs");
      buffer.startArray();
      for (uint256 i = 0; i < self.bytesArgs.length; ++i) {
        buffer.writeBytes(self.bytesArgs[i]);
      }
      buffer.endSequence();
    }

    return buffer.buf.buf;
  }

  // @notice Initializes a Chainlink Functions Request
  // @dev Sets the codeLocation and code on the request
  // @param self The uninitialized request
  // @param codeLocation The user provided source code location
  // @param language The programming language of the user code
  // @param source The user provided source code or a url
  function initializeRequest(
    Request memory self,
    Location codeLocation,
    CodeLanguage language,
    string memory source
  ) internal pure {
    if (bytes(source).length == 0) revert EmptySource();

    self.codeLocation = codeLocation;
    self.language = language;
    self.source = source;
  }

  // @notice Initializes a Chainlink Functions Request
  // @dev Simplified version of initializeRequest for PoC
  // @param self The uninitialized request
  // @param javaScriptSource The user provided JS code (must not be empty)
  function initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure {
    initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource);
  }

  // @notice Adds Remote user encrypted secrets to a Request
  // @param self The initialized request
  // @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets
  function addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure {
    if (encryptedSecretsReference.length == 0) revert EmptySecrets();

    self.secretsLocation = Location.Remote;
    self.encryptedSecretsReference = encryptedSecretsReference;
  }

  // @notice Adds DON-hosted secrets reference to a Request
  // @param self The initialized request
  // @param slotID Slot ID of the user's secrets hosted on DON
  // @param version User data version (for the slotID)
  function addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure {
    CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE);

    buffer.writeString("slotID");
    buffer.writeUInt64(slotID);
    buffer.writeString("version");
    buffer.writeUInt64(version);

    self.secretsLocation = Location.DONHosted;
    self.encryptedSecretsReference = buffer.buf.buf;
  }

  // @notice Sets args for the user run function
  // @param self The initialized request
  // @param args The array of string args (must not be empty)
  function setArgs(Request memory self, string[] memory args) internal pure {
    if (args.length == 0) revert EmptyArgs();

    self.args = args;
  }

  // @notice Sets bytes args for the user run function
  // @param self The initialized request
  // @param args The array of bytes args (must not be empty)
  function setBytesArgs(Request memory self, bytes[] memory args) internal pure {
    if (args.length == 0) revert EmptyArgs();

    self.bytesArgs = args;
  }
}

// File: contracts/@chainlink/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsResponse.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IFunctionsSubscriptions} from "../interfaces/IFunctionsSubscriptions.sol";

// @title Library of types that are used for fulfillment of a Functions request
library FunctionsResponse {
  // Used to send request information from the Router to the Coordinator
  struct RequestMeta {
    bytes data; // ══════════════════╸ CBOR encoded Chainlink Functions request data, use FunctionsRequest library to encode a request
    bytes32 flags; // ═══════════════╸ Per-subscription flags
    address requestingContract; // ══╗ The client contract that is sending the request
    uint96 availableBalance; // ═════╝ Common LINK balance of the subscription that is controlled by the Router to be used for all consumer requests.
    uint72 adminFee; // ═════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network
    uint64 subscriptionId; //        ║ Identifier of the billing subscription that will be charged for the request
    uint64 initiatedRequests; //     ║ The number of requests that have been started
    uint32 callbackGasLimit; //      ║ The amount of gas that the callback to the consuming contract will be given
    uint16 dataVersion; // ══════════╝ The version of the structure of the CBOR encoded request data
    uint64 completedRequests; // ════╗ The number of requests that have successfully completed or timed out
    address subscriptionOwner; // ═══╝ The owner of the billing subscription
  }

  enum FulfillResult {
    FULFILLED, // 0
    USER_CALLBACK_ERROR, // 1
    INVALID_REQUEST_ID, // 2
    COST_EXCEEDS_COMMITMENT, // 3
    INSUFFICIENT_GAS_PROVIDED, // 4
    SUBSCRIPTION_BALANCE_INVARIANT_VIOLATION, // 5
    INVALID_COMMITMENT // 6
  }

  struct Commitment {
    bytes32 requestId; // ═════════════════╸ A unique identifier for a Chainlink Functions request
    address coordinator; // ═══════════════╗ The Coordinator contract that manages the DON that is servicing a request
    uint96 estimatedTotalCostJuels; // ════╝ The maximum cost in Juels (1e18) of LINK that will be charged to fulfill a request
    address client; // ════════════════════╗ The client contract that sent the request
    uint64 subscriptionId; //              ║ Identifier of the billing subscription that will be charged for the request
    uint32 callbackGasLimit; // ═══════════╝ The amount of gas that the callback to the consuming contract will be given
    uint72 adminFee; // ═══════════════════╗ Flat fee (in Juels of LINK) that will be paid to the Router Owner for operation of the network
    uint72 donFee; //                      ║ Fee (in Juels of LINK) that will be split between Node Operators for servicing a request
    uint40 gasOverheadBeforeCallback; //   ║ Represents the average gas execution cost before the fulfillment callback.
    uint40 gasOverheadAfterCallback; //    ║ Represents the average gas execution cost after the fulfillment callback.
    uint32 timeoutTimestamp; // ═══════════╝ The timestamp at which a request will be eligible to be timed out
  }
}

// File: contracts/@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./ConfirmedOwnerWithProposal.sol";

/**
 * @title The ConfirmedOwner contract
 * @notice A contract with helpers for basic contract ownership.
 */
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
  constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}

// File: contracts/@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../interfaces/IOwnable.sol";

/**
 * @title The ConfirmedOwner contract
 * @notice A contract with helpers for basic contract ownership.
 */
contract ConfirmedOwnerWithProposal is IOwnable {
  address private s_owner;
  address private s_pendingOwner;

  event OwnershipTransferRequested(address indexed from, address indexed to);
  event OwnershipTransferred(address indexed from, address indexed to);

  constructor(address newOwner, address pendingOwner) {
    require(newOwner != address(0), "Cannot set owner to zero");

    s_owner = newOwner;
    if (pendingOwner != address(0)) {
      _transferOwnership(pendingOwner);
    }
  }

  /**
   * @notice Allows an owner to begin transferring ownership to a new address,
   * pending.
   */
  function transferOwnership(address to) public override onlyOwner {
    _transferOwnership(to);
  }

  /**
   * @notice Allows an ownership transfer to be completed by the recipient.
   */
  function acceptOwnership() external override {
    require(msg.sender == s_pendingOwner, "Must be proposed owner");

    address oldOwner = s_owner;
    s_owner = msg.sender;
    s_pendingOwner = address(0);

    emit OwnershipTransferred(oldOwner, msg.sender);
  }

  /**
   * @notice Get the current owner
   */
  function owner() public view override returns (address) {
    return s_owner;
  }

  /**
   * @notice validate, transfer ownership, and emit relevant events
   */
  function _transferOwnership(address to) private {
    require(to != msg.sender, "Cannot transfer to self");

    s_pendingOwner = to;

    emit OwnershipTransferRequested(s_owner, to);
  }

  /**
   * @notice validate access
   */
  function _validateOwnership() internal view {
    require(msg.sender == s_owner, "Only callable by owner");
  }

  /**
   * @notice Reverts if called by anyone other than the contract owner.
   */
  modifier onlyOwner() {
    _validateOwnership();
    _;
  }
}

// File: contracts/@chainlink/contracts/src/v0.8/shared/interfaces/IOwnable.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IOwnable {
  function owner() external returns (address);

  function transferOwnership(address recipient) external;

  function acceptOwnership() external;
}

// File: contracts/@chainlink/contracts/src/v0.8/vendor/@ensdomains/buffer/0.1.0/Buffer.sol



// SPDX-License-Identifier: BSD-2-Clause
pragma solidity ^0.8.4;

/**
 * @dev A library for working with mutable byte buffers in Solidity.
 *
 * Byte buffers are mutable and expandable, and provide a variety of primitives
 * for appending to them. At any time you can fetch a bytes object containing the
 * current contents of the buffer. The bytes object should not be stored between
 * operations, as it may change due to resizing of the buffer.
 */
library Buffer {
  /**
   * @dev Represents a mutable buffer. Buffers have a current value (buf) and
   *      a capacity. The capacity may be longer than the current value, in
   *      which case it can be extended without the need to allocate more memory.
   */
  struct buffer {
    bytes buf;
    uint256 capacity;
  }

  /**
   * @dev Initializes a buffer with an initial capacity.
   * @param buf The buffer to initialize.
   * @param capacity The number of bytes of space to allocate the buffer.
   * @return The buffer, for chaining.
   */
  function init(buffer memory buf, uint256 capacity) internal pure returns (buffer memory) {
    if (capacity % 32 != 0) {
      capacity += 32 - (capacity % 32);
    }
    // Allocate space for the buffer data
    buf.capacity = capacity;
    assembly {
      let ptr := mload(0x40)
      mstore(buf, ptr)
      mstore(ptr, 0)
      let fpm := add(32, add(ptr, capacity))
      if lt(fpm, ptr) {
        revert(0, 0)
      }
      mstore(0x40, fpm)
    }
    return buf;
  }

  /**
   * @dev Initializes a new buffer from an existing bytes object.
   *      Changes to the buffer may mutate the original value.
   * @param b The bytes object to initialize the buffer with.
   * @return A new buffer.
   */
  function fromBytes(bytes memory b) internal pure returns (buffer memory) {
    buffer memory buf;
    buf.buf = b;
    buf.capacity = b.length;
    return buf;
  }

  function resize(buffer memory buf, uint256 capacity) private pure {
    bytes memory oldbuf = buf.buf;
    init(buf, capacity);
    append(buf, oldbuf);
  }

  /**
   * @dev Sets buffer length to 0.
   * @param buf The buffer to truncate.
   * @return The original buffer, for chaining..
   */
  function truncate(buffer memory buf) internal pure returns (buffer memory) {
    assembly {
      let bufptr := mload(buf)
      mstore(bufptr, 0)
    }
    return buf;
  }

  /**
   * @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @param len The number of bytes to copy.
   * @return The original buffer, for chaining.
   */
  function append(buffer memory buf, bytes memory data, uint256 len) internal pure returns (buffer memory) {
    require(len <= data.length);

    uint256 off = buf.buf.length;
    uint256 newCapacity = off + len;
    if (newCapacity > buf.capacity) {
      resize(buf, newCapacity * 2);
    }

    uint256 dest;
    uint256 src;
    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Length of existing buffer data
      let buflen := mload(bufptr)
      // Start address = buffer address + offset + sizeof(buffer length)
      dest := add(add(bufptr, 32), off)
      // Update buffer length if we're extending it
      if gt(newCapacity, buflen) {
        mstore(bufptr, newCapacity)
      }
      src := add(data, 32)
    }

    // Copy word-length chunks while possible
    for (; len >= 32; len -= 32) {
      assembly {
        mstore(dest, mload(src))
      }
      dest += 32;
      src += 32;
    }

    // Copy remaining bytes
    unchecked {
      uint256 mask = (256 ** (32 - len)) - 1;
      assembly {
        let srcpart := and(mload(src), not(mask))
        let destpart := and(mload(dest), mask)
        mstore(dest, or(destpart, srcpart))
      }
    }

    return buf;
  }

  /**
   * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
    return append(buf, data, data.length);
  }

  /**
   * @dev Appends a byte to the buffer. Resizes if doing so would exceed the
   *      capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function appendUint8(buffer memory buf, uint8 data) internal pure returns (buffer memory) {
    uint256 off = buf.buf.length;
    uint256 offPlusOne = off + 1;
    if (off >= buf.capacity) {
      resize(buf, offPlusOne * 2);
    }

    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Address = buffer address + sizeof(buffer length) + off
      let dest := add(add(bufptr, off), 32)
      mstore8(dest, data)
      // Update buffer length if we extended it
      if gt(offPlusOne, mload(bufptr)) {
        mstore(bufptr, offPlusOne)
      }
    }

    return buf;
  }

  /**
   * @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would
   *      exceed the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @param len The number of bytes to write (left-aligned).
   * @return The original buffer, for chaining.
   */
  function append(buffer memory buf, bytes32 data, uint256 len) private pure returns (buffer memory) {
    uint256 off = buf.buf.length;
    uint256 newCapacity = len + off;
    if (newCapacity > buf.capacity) {
      resize(buf, newCapacity * 2);
    }

    unchecked {
      uint256 mask = (256 ** len) - 1;
      // Right-align data
      data = data >> (8 * (32 - len));
      assembly {
        // Memory address of the buffer data
        let bufptr := mload(buf)
        // Address = buffer address + sizeof(buffer length) + newCapacity
        let dest := add(bufptr, newCapacity)
        mstore(dest, or(and(mload(dest), not(mask)), data))
        // Update buffer length if we extended it
        if gt(newCapacity, mload(bufptr)) {
          mstore(bufptr, newCapacity)
        }
      }
    }
    return buf;
  }

  /**
   * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chhaining.
   */
  function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
    return append(buf, bytes32(data), 20);
  }

  /**
   * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
    return append(buf, data, 32);
  }

  /**
   * @dev Appends a byte to the end of the buffer. Resizes if doing so would
   *      exceed the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @param len The number of bytes to write (right-aligned).
   * @return The original buffer.
   */
  function appendInt(buffer memory buf, uint256 data, uint256 len) internal pure returns (buffer memory) {
    uint256 off = buf.buf.length;
    uint256 newCapacity = len + off;
    if (newCapacity > buf.capacity) {
      resize(buf, newCapacity * 2);
    }

    uint256 mask = (256 ** len) - 1;
    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Address = buffer address + sizeof(buffer length) + newCapacity
      let dest := add(bufptr, newCapacity)
      mstore(dest, or(and(mload(dest), not(mask)), data))
      // Update buffer length if we extended it
      if gt(newCapacity, mload(bufptr)) {
        mstore(bufptr, newCapacity)
      }
    }
    return buf;
  }
}

// File: contracts/@chainlink/contracts/src/v0.8/vendor/solidity-cborutils/v2.0.0/CBOR.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "../../@ensdomains/buffer/0.1.0/Buffer.sol";

/**
 * @dev A library for populating CBOR encoded payload in Solidity.
 *
 * https://datatracker.ietf.org/doc/html/rfc7049
 *
 * The library offers various write* and start* methods to encode values of different types.
 * The resulted buffer can be obtained with data() method.
 * Encoding of primitive types is staightforward, whereas encoding of sequences can result
 * in an invalid CBOR if start/write/end flow is violated.
 * For the purpose of gas saving, the library does not verify start/write/end flow internally,
 * except for nested start/end pairs.
 */

library CBOR {
  using Buffer for Buffer.buffer;

  struct CBORBuffer {
    Buffer.buffer buf;
    uint256 depth;
  }

  uint8 private constant MAJOR_TYPE_INT = 0;
  uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
  uint8 private constant MAJOR_TYPE_BYTES = 2;
  uint8 private constant MAJOR_TYPE_STRING = 3;
  uint8 private constant MAJOR_TYPE_ARRAY = 4;
  uint8 private constant MAJOR_TYPE_MAP = 5;
  uint8 private constant MAJOR_TYPE_TAG = 6;
  uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;

  uint8 private constant TAG_TYPE_BIGNUM = 2;
  uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3;

  uint8 private constant CBOR_FALSE = 20;
  uint8 private constant CBOR_TRUE = 21;
  uint8 private constant CBOR_NULL = 22;
  uint8 private constant CBOR_UNDEFINED = 23;

  function create(uint256 capacity) internal pure returns (CBORBuffer memory cbor) {
    Buffer.init(cbor.buf, capacity);
    cbor.depth = 0;
    return cbor;
  }

  function data(CBORBuffer memory buf) internal pure returns (bytes memory) {
    require(buf.depth == 0, "Invalid CBOR");
    return buf.buf.buf;
  }

  function writeUInt256(CBORBuffer memory buf, uint256 value) internal pure {
    buf.buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM));
    writeBytes(buf, abi.encode(value));
  }

  function writeInt256(CBORBuffer memory buf, int256 value) internal pure {
    if (value < 0) {
      buf.buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM));
      writeBytes(buf, abi.encode(uint256(-1 - value)));
    } else {
      writeUInt256(buf, uint256(value));
    }
  }

  function writeUInt64(CBORBuffer memory buf, uint64 value) internal pure {
    writeFixedNumeric(buf, MAJOR_TYPE_INT, value);
  }

  function writeInt64(CBORBuffer memory buf, int64 value) internal pure {
    if (value >= 0) {
      writeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value));
    } else {
      writeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(-1 - value));
    }
  }

  function writeBytes(CBORBuffer memory buf, bytes memory value) internal pure {
    writeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length));
    buf.buf.append(value);
  }

  function writeString(CBORBuffer memory buf, string memory value) internal pure {
    writeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length));
    buf.buf.append(bytes(value));
  }

  function writeBool(CBORBuffer memory buf, bool value) internal pure {
    writeContentFree(buf, value ? CBOR_TRUE : CBOR_FALSE);
  }

  function writeNull(CBORBuffer memory buf) internal pure {
    writeContentFree(buf, CBOR_NULL);
  }

  function writeUndefined(CBORBuffer memory buf) internal pure {
    writeContentFree(buf, CBOR_UNDEFINED);
  }

  function startArray(CBORBuffer memory buf) internal pure {
    writeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
    buf.depth += 1;
  }

  function startFixedArray(CBORBuffer memory buf, uint64 length) internal pure {
    writeDefiniteLengthType(buf, MAJOR_TYPE_ARRAY, length);
  }

  function startMap(CBORBuffer memory buf) internal pure {
    writeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
    buf.depth += 1;
  }

  function startFixedMap(CBORBuffer memory buf, uint64 length) internal pure {
    writeDefiniteLengthType(buf, MAJOR_TYPE_MAP, length);
  }

  function endSequence(CBORBuffer memory buf) internal pure {
    writeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
    buf.depth -= 1;
  }

  function writeKVString(CBORBuffer memory buf, string memory key, string memory value) internal pure {
    writeString(buf, key);
    writeString(buf, value);
  }

  function writeKVBytes(CBORBuffer memory buf, string memory key, bytes memory value) internal pure {
    writeString(buf, key);
    writeBytes(buf, value);
  }

  function writeKVUInt256(CBORBuffer memory buf, string memory key, uint256 value) internal pure {
    writeString(buf, key);
    writeUInt256(buf, value);
  }

  function writeKVInt256(CBORBuffer memory buf, string memory key, int256 value) internal pure {
    writeString(buf, key);
    writeInt256(buf, value);
  }

  function writeKVUInt64(CBORBuffer memory buf, string memory key, uint64 value) internal pure {
    writeString(buf, key);
    writeUInt64(buf, value);
  }

  function writeKVInt64(CBORBuffer memory buf, string memory key, int64 value) internal pure {
    writeString(buf, key);
    writeInt64(buf, value);
  }

  function writeKVBool(CBORBuffer memory buf, string memory key, bool value) internal pure {
    writeString(buf, key);
    writeBool(buf, value);
  }

  function writeKVNull(CBORBuffer memory buf, string memory key) internal pure {
    writeString(buf, key);
    writeNull(buf);
  }

  function writeKVUndefined(CBORBuffer memory buf, string memory key) internal pure {
    writeString(buf, key);
    writeUndefined(buf);
  }

  function writeKVMap(CBORBuffer memory buf, string memory key) internal pure {
    writeString(buf, key);
    startMap(buf);
  }

  function writeKVArray(CBORBuffer memory buf, string memory key) internal pure {
    writeString(buf, key);
    startArray(buf);
  }

  function writeFixedNumeric(CBORBuffer memory buf, uint8 major, uint64 value) private pure {
    if (value <= 23) {
      buf.buf.appendUint8(uint8((major << 5) | value));
    } else if (value <= 0xFF) {
      buf.buf.appendUint8(uint8((major << 5) | 24));
      buf.buf.appendInt(value, 1);
    } else if (value <= 0xFFFF) {
      buf.buf.appendUint8(uint8((major << 5) | 25));
      buf.buf.appendInt(value, 2);
    } else if (value <= 0xFFFFFFFF) {
      buf.buf.appendUint8(uint8((major << 5) | 26));
      buf.buf.appendInt(value, 4);
    } else {
      buf.buf.appendUint8(uint8((major << 5) | 27));
      buf.buf.appendInt(value, 8);
    }
  }

  function writeIndefiniteLengthType(CBORBuffer memory buf, uint8 major) private pure {
    buf.buf.appendUint8(uint8((major << 5) | 31));
  }

  function writeDefiniteLengthType(CBORBuffer memory buf, uint8 major, uint64 length) private pure {
    writeFixedNumeric(buf, major, length);
  }

  function writeContentFree(CBORBuffer memory buf, uint8 value) private pure {
    buf.buf.appendUint8(uint8((MAJOR_TYPE_CONTENT_FREE << 5) | value));
  }
}

// File: contracts/AutomatedFunctionsConsumer.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {FunctionsClient} from "./@chainlink/contracts/src/v0.8/functions/dev/1_0_0/FunctionsClient.sol";
import {ConfirmedOwner} from "./@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol";
import {FunctionsRequest} from "./@chainlink/contracts/src/v0.8/functions/dev/1_0_0/libraries/FunctionsRequest.sol";
import {AutomationCompatibleInterface} from "@chainlink/contracts/src/v0.8/AutomationCompatible.sol";

/**
 * @title Automated Functions Consumer contract using Chainlink Automations
 * @notice This contract is for demonstration not production use.
 */
contract AutomatedFunctionsConsumer is FunctionsClient, ConfirmedOwner, AutomationCompatibleInterface {
  using FunctionsRequest for FunctionsRequest.Request;

  // State variables for Chainlink Functions
  bytes32 public donId;
  bytes public s_requestCBOR;
  uint64 public s_subscriptionId;
  uint32 public s_fulfillGasLimit;

  // State variables for Chainlink Automation
  uint256 public s_updateInterval;
  uint256 public s_lastUpkeepTimeStamp;

  event OCRResponse(bytes32 indexed requestId, bytes result, bytes err);

  /**
   * @notice Executes once when a contract is created to initialize state variables
   *
   * @param router The Functions Router contract for the network
   * @param _donId The DON Id for the DON that will execute the Function
   */
  constructor(address router, bytes32 _donId) FunctionsClient(router) ConfirmedOwner(msg.sender) {
    donId = _donId;
    s_lastUpkeepTimeStamp = 0;
  }

  /**
   * @notice Sets the bytes representing the CBOR-encoded FunctionsRequest.Request that is sent when performUpkeep is called

   * @param _subscriptionId The Functions billing subscription ID used to pay for Functions requests
   * @param _fulfillGasLimit Maximum amount of gas used to call the client contract's `handleOracleFulfillment` function
   * @param _updateInterval Time interval at which Chainlink Automation should call performUpkeep
   * @param requestCBOR Bytes representing the CBOR-encoded FunctionsRequest.Request
   */
  function setRequest(
    uint64 _subscriptionId,
    uint32 _fulfillGasLimit,
    uint256 _updateInterval,
    bytes calldata requestCBOR
  ) external onlyOwner {
    s_updateInterval = _updateInterval;
    s_subscriptionId = _subscriptionId;
    s_fulfillGasLimit = _fulfillGasLimit;
    s_requestCBOR = requestCBOR;
  }

  /**
   * @notice Used by Automation to check if performUpkeep should be called.
   *
   * The function's argument is unused in this example, but there is an option to have Automation pass custom data
   * that can be used by the checkUpkeep function.
   *
   * Returns a tuple where the first element is a boolean which determines if upkeep is needed and the
   * second element contains custom bytes data which is passed to performUpkeep when it is called by Automation.
   */
  function checkUpkeep(bytes memory) public view override returns (bool upkeepNeeded, bytes memory) {
    upkeepNeeded = (block.timestamp - s_lastUpkeepTimeStamp) > s_updateInterval;
  }

  /**
   * @notice Called by Automation to trigger a Functions request
   *
   * The function's argument is unused in this example, but there is an option to have Automation pass custom data
   * returned by checkUpkeep (See Chainlink Automation documentation)
   */
  function performUpkeep(bytes calldata) external override {
    (bool upkeepNeeded, ) = checkUpkeep("");
    require(upkeepNeeded, "Time interval not met");
    s_lastUpkeepTimeStamp = block.timestamp;

    _sendRequest(s_requestCBOR, s_subscriptionId, s_fulfillGasLimit, donId);
  }

  /**
   * @notice Callback that is invoked once the DON has resolved the request or hit an error
   *
   * @param requestId The request ID, returned by sendRequest()
   * @param response Aggregated response from the user code
   * @param err Aggregated error from the user code or from the execution pipeline
   * Either response or error parameter will be set, but never both
   */
  function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override {}

  /**
   * @notice Set the DON ID
   * @param newDonId New DON ID
   */
  function setDonId(bytes32 newDonId) external onlyOwner {
    donId = newDonId;
  }
}