ETH Price: $1,962.89 (-0.38%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Accept Ownership1463629902026-01-13 17:19:1729 days ago1768324757IN
0xCd0D0b79...1f5ab5359
0 ETH0.0000000057970.00010244
Transfer Ownersh...1463629552026-01-13 17:18:0729 days ago1768324687IN
0xCd0D0b79...1f5ab5359
0 ETH0.0000000056460.00010244
Set Bundle Feed ...1339601672025-04-01 14:51:51316 days ago1743519111IN
0xCd0D0b79...1f5ab5359
0 ETH0.0000076594610.03341301
Set Feed Admin1324601772025-02-25 21:32:11351 days ago1740519131IN
0xCd0D0b79...1f5ab5359
0 ETH0.0000512681911.06761396

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DataFeedsCache

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {IReceiver} from "../keystone/interfaces/IReceiver.sol";
import {OwnerIsCreator} from "../shared/access/OwnerIsCreator.sol";
import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
import {IDataFeedsCache} from "./interfaces/IDataFeedsCache.sol";
import {ITokenRecover} from "./interfaces/ITokenRecover.sol";

import {IERC165} from "../vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC165.sol";
import {IERC20} from "../vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "../vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/utils/SafeERC20.sol";

contract DataFeedsCache is IDataFeedsCache, IReceiver, ITokenRecover, ITypeAndVersion, OwnerIsCreator {
  using SafeERC20 for IERC20;

  string public constant override typeAndVersion = "DataFeedsCache 1.0.0";

  // solhint-disable-next-line
  uint256 public constant override version = 7;

  /// Cache State

  struct WorkflowMetadata {
    address allowedSender; // Address of the sender allowed to send new reports
    address allowedWorkflowOwner; // ─╮ Address of the workflow owner
    bytes10 allowedWorkflowName; // ──╯ Name of the workflow
  }

  struct FeedConfig {
    uint8[] bundleDecimals; // Only appliciable to Bundle reports - Decimal reports have decimals encoded into the DataId.
    string description; // Description of the feed (e.g. "LINK / USD")
    WorkflowMetadata[] workflowMetadata; // Metadata for the feed
  }

  struct ReceivedBundleReport {
    bytes32 dataId; // Data ID of the feed from the received report
    uint32 timestamp; // Timestamp of the feed from the received report
    bytes bundle; // Report data in raw bytes
  }

  struct ReceivedDecimalReport {
    bytes32 dataId; // Data ID of the feed from the received report
    uint32 timestamp; // ─╮ Timestamp of the feed from the received report
    uint224 answer; // ───╯  Report data in uint224
  }

  struct StoredBundleReport {
    bytes bundle; // The latest bundle report stored for a feed
    uint32 timestamp; // The timestamp of the latest bundle report
  }

  struct StoredDecimalReport {
    uint224 answer; // ───╮ The latest decimal report stored for a feed
    uint32 timestamp; // ─╯ The timestamp of the latest decimal report
  }

  /// The message sender determines which feed is being requested, as each proxy has a single associated feed
  mapping(address aggProxy => bytes16 dataId) private s_aggregatorProxyToDataId;

  /// The latest decimal reports for each decimal feed. This will always equal s_decimalReports[s_dataIdToRoundId[dataId]][dataId]
  mapping(bytes16 dataId => StoredDecimalReport) private s_latestDecimalReports;

  /// Decimal reports for each feed, per round
  mapping(uint256 roundId => mapping(bytes16 dataId => StoredDecimalReport)) private s_decimalReports;

  /// The latest bundle reports for each bundle feed
  mapping(bytes16 dataId => StoredBundleReport) private s_latestBundleReports;

  /// The latest round id for each feed
  mapping(bytes16 dataId => uint256 roundId) private s_dataIdToRoundId;

  /// Addresses that are permitted to configure all feeds
  mapping(address feedAdmin => bool isFeedAdmin) private s_feedAdmins;

  mapping(bytes16 dataId => FeedConfig) private s_feedConfigs;

  /// Whether a given Sender and Workflow have permission to write feed updates.
  /// reportHash is the keccak256 hash of the abi.encoded(dataId, sender, workflowOwner and workflowName)
  mapping(bytes32 reportHash => bool) private s_writePermissions;

  event BundleReportUpdated(bytes16 indexed dataId, uint256 indexed timestamp, bytes bundle);
  event DecimalReportUpdated(
    bytes16 indexed dataId, uint256 indexed roundId, uint256 indexed timestamp, uint224 answer
  );
  event DecimalFeedConfigSet(
    bytes16 indexed dataId, uint8 decimals, string description, WorkflowMetadata[] workflowMetadata
  );
  event BundleFeedConfigSet(
    bytes16 indexed dataId, uint8[] decimals, string description, WorkflowMetadata[] workflowMetadata
  );
  event FeedConfigRemoved(bytes16 indexed dataId);
  event TokenRecovered(address indexed token, address indexed to, uint256 amount);

  event FeedAdminSet(address indexed feedAdmin, bool indexed isAdmin);

  event ProxyDataIdRemoved(address indexed proxy, bytes16 indexed dataId);
  event ProxyDataIdUpdated(address indexed proxy, bytes16 indexed dataId);

  event InvalidUpdatePermission(bytes16 indexed dataId, address sender, address workflowOwner, bytes10 workflowName);
  event StaleDecimalReport(bytes16 indexed dataId, uint256 reportTimestamp, uint256 latestTimestamp);
  event StaleBundleReport(bytes16 indexed dataId, uint256 reportTimestamp, uint256 latestTimestamp);

  error ArrayLengthMismatch();
  error EmptyConfig();
  error ErrorSendingNative(address to, uint256 amount, bytes data);
  error FeedNotConfigured(bytes16 dataId);
  error InsufficientBalance(uint256 balance, uint256 requiredBalance);
  error InvalidAddress(address addr);
  error InvalidDataId();
  error InvalidWorkflowName(bytes10 workflowName);
  error UnauthorizedCaller(address caller);
  error NoMappingForSender(address proxy);

  modifier onlyFeedAdmin() {
    if (!s_feedAdmins[msg.sender]) revert UnauthorizedCaller(msg.sender);
    _;
  }

  /// @inheritdoc IERC165
  function supportsInterface(
    bytes4 interfaceId
  ) public pure returns (bool) {
    return (
      interfaceId == type(IDataFeedsCache).interfaceId || interfaceId == type(IERC165).interfaceId
        || interfaceId == type(IReceiver).interfaceId || interfaceId == type(ITokenRecover).interfaceId
        || interfaceId == type(ITypeAndVersion).interfaceId
    );
  }

  /// @notice Get the workflow metadata of a feed
  /// @param dataId data ID of the feed
  /// @param startIndex The cursor to start fetching the metadata from
  /// @param maxCount The number of metadata to fetch
  /// @return workflowMetadata The metadata of the feed
  function getFeedMetadata(
    bytes16 dataId,
    uint256 startIndex,
    uint256 maxCount
  ) external view returns (WorkflowMetadata[] memory workflowMetadata) {
    FeedConfig storage feedConfig = s_feedConfigs[dataId];

    uint256 workflowMetadataLength = feedConfig.workflowMetadata.length;

    if (workflowMetadataLength == 0) {
      revert FeedNotConfigured(dataId);
    }

    if (startIndex >= workflowMetadataLength) return new WorkflowMetadata[](0);
    uint256 endIndex = startIndex + maxCount;
    endIndex = endIndex > workflowMetadataLength || maxCount == 0 ? workflowMetadataLength : endIndex;

    workflowMetadata = new WorkflowMetadata[](endIndex - startIndex);
    for (uint256 idx; idx < workflowMetadata.length; idx++) {
      workflowMetadata[idx] = feedConfig.workflowMetadata[idx + startIndex];
    }

    return workflowMetadata;
  }

  /// @notice Checks to see if this data ID, msg.sender, workflow owner, and workflow name are permissioned
  /// @param dataId The data ID for the feed
  /// @param workflowMetadata workflow metadata
  function checkFeedPermission(
    bytes16 dataId,
    WorkflowMetadata memory workflowMetadata
  ) external view returns (bool hasPermission) {
    bytes32 permission = _createReportHash(
      dataId,
      workflowMetadata.allowedSender,
      workflowMetadata.allowedWorkflowOwner,
      workflowMetadata.allowedWorkflowName
    );
    return s_writePermissions[permission];
  }

  // ================================================================
  // │                  Contract Config Interface                   │
  // ================================================================

  /// @notice Initializes the config for a decimal feed
  /// @param dataIds The data IDs of the feeds to configure
  /// @param descriptions The descriptions of the feeds
  /// @param workflowMetadata List of workflow metadata (owners, senders, and names) for every feed
  function setDecimalFeedConfigs(
    bytes16[] calldata dataIds,
    string[] calldata descriptions,
    WorkflowMetadata[] calldata workflowMetadata
  ) external onlyFeedAdmin {
    if (workflowMetadata.length == 0 || dataIds.length == 0) {
      revert EmptyConfig();
    }

    if (dataIds.length != descriptions.length) {
      revert ArrayLengthMismatch();
    }

    for (uint256 i; i < dataIds.length; ++i) {
      bytes16 dataId = dataIds[i];
      if (dataId == bytes16(0)) revert InvalidDataId();
      FeedConfig storage feedConfig = s_feedConfigs[dataId];

      if (feedConfig.workflowMetadata.length > 0) {
        // Feed is already configured, remove the previous config
        for (uint256 j; j < feedConfig.workflowMetadata.length; ++j) {
          WorkflowMetadata memory feedCurrentWorkflowMetadata = feedConfig.workflowMetadata[j];
          bytes32 reportHash = _createReportHash(
            dataId,
            feedCurrentWorkflowMetadata.allowedSender,
            feedCurrentWorkflowMetadata.allowedWorkflowOwner,
            feedCurrentWorkflowMetadata.allowedWorkflowName
          );
          delete s_writePermissions[reportHash];
        }

        delete s_feedConfigs[dataId];

        emit FeedConfigRemoved(dataId);
      }

      for (uint256 j; j < workflowMetadata.length; ++j) {
        WorkflowMetadata memory feedWorkflowMetadata = workflowMetadata[j];
        // Do those checks only once for the first data id
        if (i == 0) {
          if (feedWorkflowMetadata.allowedSender == address(0)) {
            revert InvalidAddress(feedWorkflowMetadata.allowedSender);
          }
          if (feedWorkflowMetadata.allowedWorkflowOwner == address(0)) {
            revert InvalidAddress(feedWorkflowMetadata.allowedWorkflowOwner);
          }
          if (feedWorkflowMetadata.allowedWorkflowName == bytes10(0)) {
            revert InvalidWorkflowName(feedWorkflowMetadata.allowedWorkflowName);
          }
        }

        bytes32 reportHash = _createReportHash(
          dataId,
          feedWorkflowMetadata.allowedSender,
          feedWorkflowMetadata.allowedWorkflowOwner,
          feedWorkflowMetadata.allowedWorkflowName
        );
        s_writePermissions[reportHash] = true;
        feedConfig.workflowMetadata.push(feedWorkflowMetadata);
      }

      feedConfig.description = descriptions[i];

      emit DecimalFeedConfigSet({
        dataId: dataId,
        decimals: _getDecimals(dataId),
        description: descriptions[i],
        workflowMetadata: workflowMetadata
      });
    }
  }

  /// @notice Initializes the config for a bundle feed
  /// @param dataIds The data IDs of the feeds to configure
  /// @param descriptions The descriptions of the feeds
  /// @param decimalsMatrix The number of decimals for each data point in the bundle for the feed
  /// @param workflowMetadata List of workflow metadata (owners, senders, and names) for every feed
  function setBundleFeedConfigs(
    bytes16[] calldata dataIds,
    string[] calldata descriptions,
    uint8[][] calldata decimalsMatrix,
    WorkflowMetadata[] calldata workflowMetadata
  ) external onlyFeedAdmin {
    if (workflowMetadata.length == 0 || dataIds.length == 0) {
      revert EmptyConfig();
    }

    if (dataIds.length != descriptions.length || dataIds.length != decimalsMatrix.length) {
      revert ArrayLengthMismatch();
    }

    for (uint256 i; i < dataIds.length; ++i) {
      bytes16 dataId = dataIds[i];
      if (dataId == bytes16(0)) revert InvalidDataId();
      FeedConfig storage feedConfig = s_feedConfigs[dataId];

      if (feedConfig.workflowMetadata.length > 0) {
        // Feed is already configured, remove the previous config
        for (uint256 j; j < feedConfig.workflowMetadata.length; ++j) {
          WorkflowMetadata memory feedCurrentWorkflowMetadata = feedConfig.workflowMetadata[j];
          bytes32 reportHash = _createReportHash(
            dataId,
            feedCurrentWorkflowMetadata.allowedSender,
            feedCurrentWorkflowMetadata.allowedWorkflowOwner,
            feedCurrentWorkflowMetadata.allowedWorkflowName
          );
          delete s_writePermissions[reportHash];
        }

        delete s_feedConfigs[dataId];

        emit FeedConfigRemoved(dataId);
      }

      for (uint256 j; j < workflowMetadata.length; ++j) {
        WorkflowMetadata memory feedWorkflowMetadata = workflowMetadata[j];
        // Do those checks only once for the first data id
        if (i == 0) {
          if (feedWorkflowMetadata.allowedSender == address(0)) {
            revert InvalidAddress(feedWorkflowMetadata.allowedSender);
          }
          if (feedWorkflowMetadata.allowedWorkflowOwner == address(0)) {
            revert InvalidAddress(feedWorkflowMetadata.allowedWorkflowOwner);
          }
          if (feedWorkflowMetadata.allowedWorkflowName == bytes10(0)) {
            revert InvalidWorkflowName(feedWorkflowMetadata.allowedWorkflowName);
          }
        }

        bytes32 reportHash = _createReportHash(
          dataId,
          feedWorkflowMetadata.allowedSender,
          feedWorkflowMetadata.allowedWorkflowOwner,
          feedWorkflowMetadata.allowedWorkflowName
        );
        s_writePermissions[reportHash] = true;
        feedConfig.workflowMetadata.push(feedWorkflowMetadata);
      }

      feedConfig.bundleDecimals = decimalsMatrix[i];
      feedConfig.description = descriptions[i];

      emit BundleFeedConfigSet({
        dataId: dataId,
        decimals: decimalsMatrix[i],
        description: descriptions[i],
        workflowMetadata: workflowMetadata
      });
    }
  }

  /// @notice Removes feeds and all associated data, for a set of feeds
  /// @param dataIds And array of data IDs to delete the data and configs of
  function removeFeedConfigs(
    bytes16[] calldata dataIds
  ) external onlyFeedAdmin {
    for (uint256 i; i < dataIds.length; ++i) {
      bytes16 dataId = dataIds[i];
      if (s_feedConfigs[dataId].workflowMetadata.length == 0) revert FeedNotConfigured(dataId);

      for (uint256 j; j < s_feedConfigs[dataId].workflowMetadata.length; ++j) {
        WorkflowMetadata memory feedWorkflowMetadata = s_feedConfigs[dataId].workflowMetadata[j];
        bytes32 reportHash = _createReportHash(
          dataId,
          feedWorkflowMetadata.allowedSender,
          feedWorkflowMetadata.allowedWorkflowOwner,
          feedWorkflowMetadata.allowedWorkflowName
        );
        delete s_writePermissions[reportHash];
      }

      delete s_feedConfigs[dataId];

      emit FeedConfigRemoved(dataId);
    }
  }

  /// @notice Sets a feed admin for all feeds, only callable by the Owner
  /// @param feedAdmin The feed admin
  function setFeedAdmin(address feedAdmin, bool isAdmin) external onlyOwner {
    if (feedAdmin == address(0)) revert InvalidAddress(feedAdmin);

    s_feedAdmins[feedAdmin] = isAdmin;
    emit FeedAdminSet(feedAdmin, isAdmin);
  }

  /// @notice Returns a bool is an address has feed admin permission for all feeds
  /// @param feedAdmin The feed admin
  /// @return isFeedAdmin bool if the address is the feed admin for all feeds
  function isFeedAdmin(
    address feedAdmin
  ) external view returns (bool) {
    return s_feedAdmins[feedAdmin];
  }

  /// @inheritdoc IDataFeedsCache
  function updateDataIdMappingsForProxies(
    address[] calldata proxies,
    bytes16[] calldata dataIds
  ) external onlyFeedAdmin {
    uint256 numberOfProxies = proxies.length;
    if (numberOfProxies != dataIds.length) revert ArrayLengthMismatch();

    for (uint256 i; i < numberOfProxies; i++) {
      s_aggregatorProxyToDataId[proxies[i]] = dataIds[i];

      emit ProxyDataIdUpdated(proxies[i], dataIds[i]);
    }
  }

  /// @inheritdoc IDataFeedsCache
  function getDataIdForProxy(
    address proxy
  ) external view returns (bytes16 dataId) {
    return s_aggregatorProxyToDataId[proxy];
  }

  /// @inheritdoc IDataFeedsCache
  function removeDataIdMappingsForProxies(
    address[] calldata proxies
  ) external onlyFeedAdmin {
    uint256 numberOfProxies = proxies.length;

    for (uint256 i; i < numberOfProxies; i++) {
      address proxy = proxies[i];
      bytes16 dataId = s_aggregatorProxyToDataId[proxy];
      delete s_aggregatorProxyToDataId[proxy];
      emit ProxyDataIdRemoved(proxy, dataId);
    }
  }

  // ================================================================
  // │                   Token Transfer Interface                   │
  // ================================================================

  /// @inheritdoc ITokenRecover
  function recoverTokens(IERC20 token, address to, uint256 amount) external onlyOwner {
    if (address(token) == address(0)) {
      if (amount > address(this).balance) {
        revert InsufficientBalance(address(this).balance, amount);
      }
      (bool success, bytes memory data) = to.call{value: amount}("");
      if (!success) revert ErrorSendingNative(to, amount, data);
    } else {
      if (amount > token.balanceOf(address(this))) {
        revert InsufficientBalance(token.balanceOf(address(this)), amount);
      }
      token.safeTransfer(to, amount);
    }
    emit TokenRecovered(address(token), to, amount);
  }

  // ================================================================
  // │                    Cache Update Interface                    │
  // ================================================================

  /// @inheritdoc IReceiver
  function onReport(bytes calldata metadata, bytes calldata report) external {
    (address workflowOwner, bytes10 workflowName) = _getWorkflowMetaData(metadata);

    // The first 32 bytes is the offset to the array
    // The second 32 bytes is the length of the array
    uint256 numReports = uint256(bytes32(report[32:64]));

    // Decimal reports contain 96 bytes per report
    // The total length should equal to the sum of:
    // 32 bytes for the offset
    // 32 bytes for the number of reports
    // the number of reports times 96
    if (report.length == numReports * 96 + 64) {
      ReceivedDecimalReport[] memory decodedDecimalReports = abi.decode(report, (ReceivedDecimalReport[]));
      for (uint256 i; i < numReports; ++i) {
        ReceivedDecimalReport memory decodedDecimalReport = decodedDecimalReports[i];
        // single dataId can have multiple permissions, to be updated by multiple Workflows
        bytes16 dataId = bytes16(decodedDecimalReport.dataId);
        bytes32 permission = _createReportHash(dataId, msg.sender, workflowOwner, workflowName);
        if (!s_writePermissions[permission]) {
          emit InvalidUpdatePermission(dataId, msg.sender, workflowOwner, workflowName);
          continue;
        }

        if (decodedDecimalReport.timestamp <= s_latestDecimalReports[dataId].timestamp) {
          emit StaleDecimalReport(dataId, decodedDecimalReport.timestamp, s_latestDecimalReports[dataId].timestamp);
          continue;
        }

        StoredDecimalReport memory decimalReport =
          StoredDecimalReport({answer: decodedDecimalReport.answer, timestamp: decodedDecimalReport.timestamp});

        uint256 roundId = ++s_dataIdToRoundId[dataId];

        s_latestDecimalReports[dataId] = decimalReport;
        s_decimalReports[roundId][dataId] = decimalReport;

        emit DecimalReportUpdated(dataId, roundId, decimalReport.timestamp, decimalReport.answer);

        // Needed for DF1 backward compatibility
        emit NewRound(roundId, address(0), decodedDecimalReport.timestamp);
        emit AnswerUpdated(int256(uint256(decodedDecimalReport.answer)), roundId, block.timestamp);
      }
    }
    // Bundle reports contain more bytes for the offsets
    // The total length should equal to the sum of:
    // 32 bytes for the offset
    // 32 bytes for the number of reports
    // the number of reports times 224
    else {
      //For byte reports decode using ReceivedFeedReportBundle struct
      ReceivedBundleReport[] memory decodedBundleReports = abi.decode(report, (ReceivedBundleReport[]));
      for (uint256 i; i < decodedBundleReports.length; ++i) {
        ReceivedBundleReport memory decodedBundleReport = decodedBundleReports[i];
        bytes16 dataId = bytes16(decodedBundleReport.dataId);
        // same dataId can have multiple permissions
        bytes32 permission = _createReportHash(dataId, msg.sender, workflowOwner, workflowName);
        if (!s_writePermissions[permission]) {
          emit InvalidUpdatePermission(dataId, msg.sender, workflowOwner, workflowName);
          continue;
        }

        if (decodedBundleReport.timestamp <= s_latestBundleReports[dataId].timestamp) {
          emit StaleBundleReport(dataId, decodedBundleReport.timestamp, s_latestBundleReports[dataId].timestamp);
          continue;
        }

        StoredBundleReport memory bundleReport =
          StoredBundleReport({bundle: decodedBundleReport.bundle, timestamp: decodedBundleReport.timestamp});

        s_latestBundleReports[dataId] = bundleReport;

        emit BundleReportUpdated(dataId, bundleReport.timestamp, bundleReport.bundle);
      }
    }
  }
  // ================================================================
  // │                        Helper Methods                        │
  // ================================================================

  /// @notice Gets the Decimals of the feed from the data Id
  /// @param dataId The data ID for the feed
  /// @return feedDecimals The number of decimals the feed has
  function _getDecimals(
    bytes16 dataId
  ) internal pure returns (uint8 feedDecimals) {
    // Get the report type from data id. Report type has index of 7
    bytes1 reportType = _getDataType(dataId, 7);

    // For decimal reports convert to uint8, then shift
    if (reportType >= hex"20" && reportType <= hex"60") {
      return uint8(reportType) - 32;
    }

    // If not decimal type, return 0
    return 0;
  }

  /// @notice Extracts the workflow name and the workflow owner from the metadata parameter of onReport
  /// @param metadata The metadata in bytes format
  /// @return workflowOwner The owner of the workflow
  /// @return workflowName  The name of the workflow
  function _getWorkflowMetaData(
    bytes memory metadata
  ) internal pure returns (address, bytes10) {
    address workflowOwner;
    bytes10 workflowName;
    // (first 32 bytes contain length of the byte array)
    // workflow_cid             // offset 32, size 32
    // workflow_name            // offset 64, size 10
    // workflow_owner           // offset 74, size 20
    // report_name              // offset 94, size  2
    assembly {
      // no shifting needed for bytes10 type
      workflowName := mload(add(metadata, 64))
      // shift right by 12 bytes to get the actual value
      workflowOwner := shr(mul(12, 8), mload(add(metadata, 74)))
    }
    return (workflowOwner, workflowName);
  }

  /// @notice Extracts a byte from the data ID, to check data types
  /// @param dataId The data ID for the feed
  /// @param index The index of the byte to extract from the data Id
  /// @return dataType result The keccak256 hash of the abi.encoded inputs
  function _getDataType(bytes16 dataId, uint256 index) internal pure returns (bytes1 dataType) {
    // Convert bytes16 to bytes
    return abi.encodePacked(dataId)[index];
  }

  /// @notice Creates a report hash used to permission write access
  /// @param dataId The data ID for the feed
  /// @param sender The msg.sender of the transaction calling into onReport
  /// @param workflowOwner The owner of the workflow
  /// @param workflowName The name of the workflow
  /// @return reportHash The keccak256 hash of the abi.encoded inputs
  function _createReportHash(
    bytes16 dataId,
    address sender,
    address workflowOwner,
    bytes10 workflowName
  ) internal pure returns (bytes32) {
    return keccak256(abi.encode(dataId, sender, workflowOwner, workflowName));
  }

  // ================================================================
  // │                    Data Access Interface                     │
  // ================================================================

  /// Bundle Feed Interface

  function latestBundle() external view returns (bytes memory bundle) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return (s_latestBundleReports[dataId].bundle);
  }

  function bundleDecimals() external view returns (uint8[] memory bundleFeedDecimals) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return s_feedConfigs[dataId].bundleDecimals;
  }

  function latestBundleTimestamp() external view returns (uint256 timestamp) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return s_latestBundleReports[dataId].timestamp;
  }

  /// AggregatorInterface

  function latestAnswer() external view returns (int256 answer) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return int256(uint256(s_latestDecimalReports[dataId].answer));
  }

  function latestTimestamp() external view returns (uint256 timestamp) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return s_latestDecimalReports[dataId].timestamp;
  }

  function latestRound() external view returns (uint256 round) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return s_dataIdToRoundId[dataId];
  }

  function getAnswer(
    uint256 roundId
  ) external view returns (int256 answer) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return int256(uint256(s_decimalReports[roundId][dataId].answer));
  }

  function getTimestamp(
    uint256 roundId
  ) external view returns (uint256 timestamp) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return s_decimalReports[roundId][dataId].timestamp;
  }

  /// AggregatorV3Interface

  function decimals() external view returns (uint8 feedDecimals) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);
    return _getDecimals(dataId);
  }

  function description() external view returns (string memory feedDescription) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    return s_feedConfigs[dataId].description;
  }

  function getRoundData(
    uint80 roundId
  ) external view returns (uint80 id, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    uint256 timestamp = s_decimalReports[uint256(roundId)][dataId].timestamp;

    return (roundId, int256(uint256(s_decimalReports[uint256(roundId)][dataId].answer)), timestamp, timestamp, roundId);
  }

  function latestRoundData()
    external
    view
    returns (uint80 id, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
  {
    bytes16 dataId = s_aggregatorProxyToDataId[msg.sender];
    if (dataId == bytes16(0)) revert NoMappingForSender(msg.sender);

    uint80 roundId = uint80(s_dataIdToRoundId[dataId]);
    uint256 timestamp = s_latestDecimalReports[dataId].timestamp;

    return (roundId, int256(uint256(s_latestDecimalReports[dataId].answer)), timestamp, timestamp, roundId);
  }

  /// Direct access
  function getLatestBundle(
    bytes16 dataId
  ) external view returns (bytes memory bundle) {
    if (dataId == bytes16(0)) revert InvalidDataId();
    return (s_latestBundleReports[dataId].bundle);
  }

  function getBundleDecimals(
    bytes16 dataId
  ) external view returns (uint8[] memory bundleFeedDecimals) {
    if (dataId == bytes16(0)) revert InvalidDataId();
    return s_feedConfigs[dataId].bundleDecimals;
  }

  function getLatestBundleTimestamp(
    bytes16 dataId
  ) external view returns (uint256 timestamp) {
    if (dataId == bytes16(0)) revert InvalidDataId();
    return s_latestBundleReports[dataId].timestamp;
  }

  function getLatestAnswer(
    bytes16 dataId
  ) external view returns (int256 answer) {
    if (dataId == bytes16(0)) revert InvalidDataId();
    return int256(uint256(s_latestDecimalReports[dataId].answer));
  }

  function getLatestTimestamp(
    bytes16 dataId
  ) external view returns (uint256 timestamp) {
    if (dataId == bytes16(0)) revert InvalidDataId();
    return s_latestDecimalReports[dataId].timestamp;
  }

  function getLatestRoundData(
    bytes16 dataId
  ) external view returns (uint80 id, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) {
    if (dataId == bytes16(0)) revert InvalidDataId();

    uint80 roundId = uint80(s_dataIdToRoundId[dataId]);
    uint256 timestamp = s_latestDecimalReports[dataId].timestamp;

    return (roundId, int256(uint256(s_latestDecimalReports[dataId].answer)), timestamp, timestamp, roundId);
  }

  function getDecimals(
    bytes16 dataId
  ) external pure returns (uint8 feedDecimals) {
    if (dataId == bytes16(0)) revert InvalidDataId();
    return _getDecimals(dataId);
  }

  function getDescription(
    bytes16 dataId
  ) external view returns (string memory feedDescription) {
    if (dataId == bytes16(0)) revert InvalidDataId();
    return s_feedConfigs[dataId].description;
  }
}

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

import {IERC165} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol";

/// @title IReceiver - receives keystone reports
/// @notice Implementations must support the IReceiver interface through ERC165.
interface IReceiver is IERC165 {
  /// @notice Handles incoming keystone reports.
  /// @dev If this function call reverts, it can be retried with a higher gas
  /// limit. The receiver is responsible for discarding stale reports.
  /// @param metadata Report's metadata.
  /// @param report Workflow report.
  function onReport(bytes calldata metadata, bytes calldata report) external;
}

File 3 of 19 : OwnerIsCreator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ConfirmedOwner} from "./ConfirmedOwner.sol";

/// @title The OwnerIsCreator contract
/// @notice A contract with helpers for basic contract ownership.
contract OwnerIsCreator is ConfirmedOwner {
  constructor() ConfirmedOwner(msg.sender) {}
}

File 4 of 19 : ITypeAndVersion.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ITypeAndVersion {
  function typeAndVersion() external pure returns (string memory);
}

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

import {IBundleBaseAggregator} from "./IBundleBaseAggregator.sol";
import {ICommonAggregator} from "./ICommonAggregator.sol";
import {IDecimalAggregator} from "./IDecimalAggregator.sol";

/// @notice IDataFeedsCache
/// Responsible for storing data associated with a given data ID and additional request data.
interface IDataFeedsCache is IDecimalAggregator, IBundleBaseAggregator, ICommonAggregator {
  /// @notice Remove feed configs.
  /// @param dataIds List of data IDs
  function removeFeedConfigs(
    bytes16[] calldata dataIds
  ) external;

  /// @notice Update mappings for AggregatorProxy -> Data ID
  /// @param proxies AggregatorProxy addresses
  /// @param dataIds Data IDs
  function updateDataIdMappingsForProxies(address[] calldata proxies, bytes16[] calldata dataIds) external;

  /// @notice Remove mappings for AggregatorProxy -> Data IDs
  /// @param proxies  AggregatorProxy addresses to remove
  function removeDataIdMappingsForProxies(
    address[] calldata proxies
  ) external;

  /// @notice Get the Data ID mapping for a AggregatorProxy
  /// @param proxy AggregatorProxy addresses which will be reading feed data
  function getDataIdForProxy(
    address proxy
  ) external view returns (bytes16 dataId);
}

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

import {IERC20} from "./../../vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC20.sol";

/// @notice ITokenRecover
/// Implements the recoverTokens method, enabling the recovery of ERC-20 or native tokens accidentally sent to a
/// contract outside of normal operations.
interface ITokenRecover {
  /// @notice Transfer any ERC-20 or native tokens accidentally sent to this contract.
  /// @param token Token to transfer
  /// @param to Address to send payment to
  /// @param amount Amount of token to transfer
  function recoverTokens(IERC20 token, address to, uint256 amount) external;
}

File 7 of 19 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 11 of 19 : ConfirmedOwner.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ConfirmedOwnerWithProposal} from "./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)) {}
}

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

interface IBundleBaseAggregator {
  function latestBundle() external view returns (bytes memory bundle);

  function bundleDecimals() external view returns (uint8[] memory);

  function latestBundleTimestamp() external view returns (uint256);
}

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

interface ICommonAggregator {
  function description() external view returns (string memory);

  function version() external view returns (uint256);
}

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

interface IDecimalAggregator {
  function latestAnswer() external view returns (int256);

  function latestRound() external view returns (uint256);

  function latestTimestamp() external view returns (uint256);

  function getAnswer(
    uint256 roundId
  ) external view returns (int256);

  function getTimestamp(
    uint256 roundId
  ) external view returns (uint256);

  function decimals() external view returns (uint8);

  function getRoundData(
    uint80 _roundId
  ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

  function latestRoundData()
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

  event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);

  event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}

File 15 of 19 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

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

import {IOwnable} from "../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) {
    // solhint-disable-next-line gas-custom-errors
    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.
  function transferOwnership(address to) public override onlyOwner {
    _transferOwnership(to);
  }

  /// @notice Allows an ownership transfer to be completed by the recipient.
  function acceptOwnership() external override {
    // solhint-disable-next-line gas-custom-errors
    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 {
    // solhint-disable-next-line gas-custom-errors
    require(to != msg.sender, "Cannot transfer to self");

    s_pendingOwner = to;

    emit OwnershipTransferRequested(s_owner, to);
  }

  /// @notice validate access
  function _validateOwnership() internal view {
    // solhint-disable-next-line gas-custom-errors
    require(msg.sender == s_owner, "Only callable by owner");
  }

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

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

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

  function transferOwnership(address recipient) external;

  function acceptOwnership() external;
}

Settings
{
  "remappings": [
    "forge-std/=src/v0.8/vendor/forge-std/src/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@arbitrum/=node_modules/@arbitrum/",
    "hardhat/=node_modules/hardhat/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@scroll-tech/=node_modules/@scroll-tech/",
    "@zksync/=node_modules/@zksync/",
    "@offchainlabs/=node_modules/@offchainlabs/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"EmptyConfig","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"ErrorSendingNative","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"FeedNotConfigured","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"requiredBalance","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidDataId","type":"error"},{"inputs":[{"internalType":"bytes10","name":"workflowName","type":"bytes10"}],"name":"InvalidWorkflowName","type":"error"},{"inputs":[{"internalType":"address","name":"proxy","type":"address"}],"name":"NoMappingForSender","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"UnauthorizedCaller","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"int256","name":"current","type":"int256"},{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"updatedAt","type":"uint256"}],"name":"AnswerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"uint8[]","name":"decimals","type":"uint8[]"},{"indexed":false,"internalType":"string","name":"description","type":"string"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"indexed":false,"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"name":"BundleFeedConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"bundle","type":"bytes"}],"name":"BundleReportUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"},{"indexed":false,"internalType":"string","name":"description","type":"string"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"indexed":false,"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"name":"DecimalFeedConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint224","name":"answer","type":"uint224"}],"name":"DecimalReportUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feedAdmin","type":"address"},{"indexed":true,"internalType":"bool","name":"isAdmin","type":"bool"}],"name":"FeedAdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"FeedConfigRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"workflowOwner","type":"address"},{"indexed":false,"internalType":"bytes10","name":"workflowName","type":"bytes10"}],"name":"InvalidUpdatePermission","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"address","name":"startedBy","type":"address"},{"indexed":false,"internalType":"uint256","name":"startedAt","type":"uint256"}],"name":"NewRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proxy","type":"address"},{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"ProxyDataIdRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proxy","type":"address"},{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"ProxyDataIdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"uint256","name":"reportTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"latestTimestamp","type":"uint256"}],"name":"StaleBundleReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes16","name":"dataId","type":"bytes16"},{"indexed":false,"internalType":"uint256","name":"reportTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"latestTimestamp","type":"uint256"}],"name":"StaleDecimalReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenRecovered","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bundleDecimals","outputs":[{"internalType":"uint8[]","name":"bundleFeedDecimals","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"internalType":"struct DataFeedsCache.WorkflowMetadata","name":"workflowMetadata","type":"tuple"}],"name":"checkFeedPermission","outputs":[{"internalType":"bool","name":"hasPermission","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"feedDecimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"feedDescription","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getAnswer","outputs":[{"internalType":"int256","name":"answer","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getBundleDecimals","outputs":[{"internalType":"uint8[]","name":"bundleFeedDecimals","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"proxy","type":"address"}],"name":"getDataIdForProxy","outputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getDecimals","outputs":[{"internalType":"uint8","name":"feedDecimals","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getDescription","outputs":[{"internalType":"string","name":"feedDescription","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"},{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"maxCount","type":"uint256"}],"name":"getFeedMetadata","outputs":[{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestAnswer","outputs":[{"internalType":"int256","name":"answer","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestBundle","outputs":[{"internalType":"bytes","name":"bundle","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestBundleTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestRoundData","outputs":[{"internalType":"uint80","name":"id","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes16","name":"dataId","type":"bytes16"}],"name":"getLatestTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint80","name":"roundId","type":"uint80"}],"name":"getRoundData","outputs":[{"internalType":"uint80","name":"id","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"feedAdmin","type":"address"}],"name":"isFeedAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestAnswer","outputs":[{"internalType":"int256","name":"answer","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBundle","outputs":[{"internalType":"bytes","name":"bundle","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestBundleTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRound","outputs":[{"internalType":"uint256","name":"round","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"id","type":"uint80"},{"internalType":"int256","name":"answer","type":"int256"},{"internalType":"uint256","name":"startedAt","type":"uint256"},{"internalType":"uint256","name":"updatedAt","type":"uint256"},{"internalType":"uint80","name":"answeredInRound","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"bytes","name":"report","type":"bytes"}],"name":"onReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"proxies","type":"address[]"}],"name":"removeDataIdMappingsForProxies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes16[]","name":"dataIds","type":"bytes16[]"}],"name":"removeFeedConfigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes16[]","name":"dataIds","type":"bytes16[]"},{"internalType":"string[]","name":"descriptions","type":"string[]"},{"internalType":"uint8[][]","name":"decimalsMatrix","type":"uint8[][]"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"name":"setBundleFeedConfigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes16[]","name":"dataIds","type":"bytes16[]"},{"internalType":"string[]","name":"descriptions","type":"string[]"},{"components":[{"internalType":"address","name":"allowedSender","type":"address"},{"internalType":"address","name":"allowedWorkflowOwner","type":"address"},{"internalType":"bytes10","name":"allowedWorkflowName","type":"bytes10"}],"internalType":"struct DataFeedsCache.WorkflowMetadata[]","name":"workflowMetadata","type":"tuple[]"}],"name":"setDecimalFeedConfigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feedAdmin","type":"address"},{"internalType":"bool","name":"isAdmin","type":"bool"}],"name":"setFeedAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"proxies","type":"address[]"},{"internalType":"bytes16[]","name":"dataIds","type":"bytes16[]"}],"name":"updateDataIdMappingsForProxies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

608060405234801561000f575f80fd5b5033805f816100655760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b5f80546001600160a01b0319166001600160a01b0384811691909117909155811615610094576100948161009c565b505050610144565b336001600160a01b038216036100f45760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005c565b600180546001600160a01b0319166001600160a01b038381169182179092555f8054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b615632806101515f395ff3fe608060405234801561000f575f80fd5b5060043610610283575f3560e01c806379ba509711610157578063b5ab58dc116100d2578063ec52b1f511610088578063feaf968c1161006e578063feaf968c146105ff578063feb5d17214610607578063ff25dbc8146106ca575f80fd5b8063ec52b1f5146105d9578063f2fde38b146105ec575f80fd5b8063be4f0a9f116100b8578063be4f0a9f14610593578063cdd25100146105a6578063d143dcd9146105b9575f80fd5b8063b5ab58dc1461056d578063b633620c14610580575f80fd5b80639198274f116101275780639a6fc8f51161010d5780639a6fc8f51461054a5780639d91348d1461055d578063a3d610cc14610565575f80fd5b80639198274f146104d95780639608e18f146104e1575f80fd5b806379ba50971461048f578063805f2132146104975780638205bf6a146104aa5780638da5cb5b146104b2575f80fd5b80634533dc98116102015780635f25452b116101b7578063668a0f021161019d578063668a0f021461046c5780636a36e494146104745780637284e41614610487575f80fd5b80635f25452b1461040f5780635f3e849f14610459575f80fd5b806350d25bcd116101e757806350d25bcd146103ec57806354fd4d50146103f4578063557a33c2146103fc575f80fd5b80634533dc98146103b957806347381b08146103cc575f80fd5b8063297dbf561161025657806335f611221161023c57806335f611221461035b5780633a0449741461036e57806343d5ba50146103a6575f80fd5b8063297dbf561461032c578063313ce56714610341575f80fd5b806301ffc9a71461028757806302ccb3ae146102af578063181f5a77146102cf5780631bb1610c1461030b575b5f80fd5b61029a6102953660046144a9565b6106dd565b60405190151581526020015b60405180910390f35b6102c26102bd36600461451c565b610859565b6040516102a69190614581565b6102c26040518060400160405280601481526020017f446174614665656473436163686520312e302e3000000000000000000000000081525081565b61031e61031936600461451c565b610975565b6040519081526020016102a6565b61033f61033a3660046145db565b610a29565b005b610349610c24565b60405160ff90911681526020016102a6565b61033f610369366004614688565b610ca0565b61029a61037c366004614777565b73ffffffffffffffffffffffffffffffffffffffff165f9081526007602052604090205460ff1690565b6103496103b436600461451c565b61145f565b61033f6103c7366004614792565b6114c2565b6103df6103da36600461451c565b611c26565b6040516102a69190614831565b61031e611d1c565b61031e600781565b61031e61040a36600461451c565b611ddc565b61042261041d36600461451c565b611e88565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016102a6565b61033f610467366004614876565b611f7a565b61031e61226e565b6102c261048236600461451c565b612310565b6102c26123a6565b61033f6124d6565b61033f6104a53660046148f2565b6125d2565b61031e612e45565b5f5460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102a6565b6102c2612f0d565b6105196104ef366004614777565b73ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460801b90565b6040517fffffffffffffffffffffffffffffffff0000000000000000000000000000000090911681526020016102a6565b610422610558366004614952565b612fb8565b6103df6130cb565b61031e6131d6565b61031e61057b36600461497b565b613281565b61031e61058e36600461497b565b61334e565b61033f6105a1366004614992565b613424565b61033f6105b4366004614992565b613533565b6105cc6105c73660046149d1565b613898565b6040516102a69190614a01565b61033f6105e7366004614aaf565b613b3b565b61033f6105fa366004614777565b613c26565b610422613c3a565b61029a610615366004614c0b565b805160208083015160409384015184517fffffffffffffffffffffffffffffffff00000000000000000000000000000000969096168684015273ffffffffffffffffffffffffffffffffffffffff93841686860152921660608501527fffffffffffffffffffff000000000000000000000000000000000000000000009091166080808501919091528251808503909101815260a090930182528251928101929092205f908152600990925290205460ff1690565b61031e6106d836600461451c565b613d41565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167fcce8054600000000000000000000000000000000000000000000000000000000148061076f57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b806107bb57507fffffffff0000000000000000000000000000000000000000000000000000000082167f805f213200000000000000000000000000000000000000000000000000000000145b8061080757507fffffffff0000000000000000000000000000000000000000000000000000000082167f5f3e849f00000000000000000000000000000000000000000000000000000000145b8061085357507fffffffff0000000000000000000000000000000000000000000000000000000082167f181f5a7700000000000000000000000000000000000000000000000000000000145b92915050565b60607fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166108b4576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260086020526040902060010180546108f290614c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461091e90614c3d565b80156109695780601f1061094057610100808354040283529160200191610969565b820191905f5260205f20905b81548152906001019060200180831161094c57829003601f168201915b50505050509050919050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166109cf576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b335f9081526007602052604090205460ff16610a78576040517fd86ad9cf0000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b82818114610ab2576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b81811015610c1c57838382818110610ace57610ace614c8e565b9050602002016020810190610ae3919061451c565b60025f888885818110610af857610af8614c8e565b9050602002016020810190610b0d9190614777565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffff000000000000000000000000000000001660809290921c919091179055838382818110610b7457610b74614c8e565b9050602002016020810190610b89919061451c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016868683818110610bbd57610bbd614c8e565b9050602002016020810190610bd29190614777565b73ffffffffffffffffffffffffffffffffffffffff167ff31b9e58190970ef07c23d0ba78c358eb3b416e829ef484b29b9993a6b1b285a60405160405180910390a3600101610ab4565b505050505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116610c91576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b610c9a81613dd8565b91505090565b335f9081526007602052604090205460ff16610cea576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b801580610cf5575086155b15610d2c576040517f60e8b63a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8685141580610d3b5750868314155b15610d72576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b87811015611454575f898983818110610d8f57610d8f614c8e565b9050602002016020810190610da4919061451c565b90507fffffffffffffffffffffffffffffffff000000000000000000000000000000008116610dff576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260409020600281015415611025575f5b6002820154811015610f80575f826002018281548110610e5d57610e5d614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008d168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101610e3b565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260086020526040812090610fbc8282614319565b610fc9600183015f61433b565b610fd6600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25b5f5b8481101561133c575f86868381811061104257611042614c8e565b9050606002018036038101906110589190614cbb565b9050845f036111c057805173ffffffffffffffffffffffffffffffffffffffff166110ca5780516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b602081015173ffffffffffffffffffffffffffffffffffffffff166111395760208101516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b60408101517fffffffffffffffffffff00000000000000000000000000000000000000000000166111c05760408082015190517f114988d50000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff000000000000000000000000000000000000000000009091166004820152602401610a6f565b8051602080830180516040808601805182517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015273ffffffffffffffffffffffffffffffffffffffff9788168185015293871660608501527fffffffffffffffffffff00000000000000000000000000000000000000000000166080808501919091528251808503909101815260a090930182528251928501929092205f9081526009855290812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091556002898101805480840182559084529590922096519490910290950180549385167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317835590519184018054915160b01c74010000000000000000000000000000000000000000027fffff000000000000000000000000000000000000000000000000000000000000909216929093169190911717905501611027565b5086868481811061134f5761134f614c8e565b90506020028101906113619190614cd5565b61136c918391614390565b5088888481811061137f5761137f614c8e565b90506020028101906113919190614d39565b60018301916113a1919083614de5565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082167fdfebe0878c5611549f54908260ca12271c7ff3f0ebae0c1de47732612403869e8888868181106113f8576113f8614c8e565b905060200281019061140a9190614cd5565b8c8c8881811061141c5761141c614c8e565b905060200281019061142e9190614d39565b8a8a60405161144296959493929190614ff3565b60405180910390a25050600101610d74565b505050505050505050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166114b9576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61085382613dd8565b335f9081526007602052604090205460ff1661150c576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b801580611517575084155b1561154e576040517f60e8b63a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b848314611587576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b85811015611c1d575f8787838181106115a4576115a4614c8e565b90506020020160208101906115b9919061451c565b90507fffffffffffffffffffffffffffffffff000000000000000000000000000000008116611614576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f90815260086020526040902060028101541561183a575f5b6002820154811015611795575f82600201828154811061167257611672614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008d168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101611650565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860205260408120906117d18282614319565b6117de600183015f61433b565b6117eb600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25b5f5b84811015611b51575f86868381811061185757611857614c8e565b90506060020180360381019061186d9190614cbb565b9050845f036119d557805173ffffffffffffffffffffffffffffffffffffffff166118df5780516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b602081015173ffffffffffffffffffffffffffffffffffffffff1661194e5760208101516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b60408101517fffffffffffffffffffff00000000000000000000000000000000000000000000166119d55760408082015190517f114988d50000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff000000000000000000000000000000000000000000009091166004820152602401610a6f565b8051602080830180516040808601805182517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015273ffffffffffffffffffffffffffffffffffffffff9788168185015293871660608501527fffffffffffffffffffff00000000000000000000000000000000000000000000166080808501919091528251808503909101815260a090930182528251928501929092205f9081526009855290812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091556002898101805480840182559084529590922096519490910290950180549385167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317835590519184018054915160b01c74010000000000000000000000000000000000000000027fffff00000000000000000000000000000000000000000000000000000000000090921692909316919091171790550161183c565b50868684818110611b6457611b64614c8e565b9050602002810190611b769190614d39565b6001830191611b86919083614de5565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082167f2dec0e9ffbb18c6499fc8bee8b9c35f765e76d9dbd436f25dd00a80de267ac0d611bd484613dd8565b898987818110611be657611be6614c8e565b9050602002810190611bf89190614d39565b8989604051611c0b95949392919061506a565b60405180910390a25050600101611589565b50505050505050565b60607fffffffffffffffffffffffffffffffff000000000000000000000000000000008216611c81576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860209081526040918290208054835181840281018401909452808452909183018282801561096957602002820191905f5260205f20905f905b825461010083900a900460ff16815260206001928301818104948501949093039092029101808411611ce3575094979650505050505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116611d89576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b5f7fffffffffffffffffffffffffffffffff000000000000000000000000000000008216611e36576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b5f808080807fffffffffffffffffffffffffffffffff000000000000000000000000000000008616611ee6576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050507fffffffffffffffffffffffffffffffff00000000000000000000000000000000919091165f9081526006602090815260408083205460039092529091205490927bffffffffffffffffffffffffffffffffffffffffffffffffffffffff821692507c010000000000000000000000000000000000000000000000000000000090910463ffffffff169081908490565b611f82613e97565b73ffffffffffffffffffffffffffffffffffffffff83166120855747811115611fe0576040517fcf47918100000000000000000000000000000000000000000000000000000000815247600482015260248101829052604401610a6f565b5f808373ffffffffffffffffffffffffffffffffffffffff16836040515f6040518083038185875af1925050503d805f8114612037576040519150601f19603f3d011682016040523d82523d5f602084013e61203c565b606091505b50915091508161207e578383826040517fc50febed000000000000000000000000000000000000000000000000000000008152600401610a6f939291906150a5565b5050612202565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156120ed573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061211191906150e2565b8111156121e1576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015612180573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121a491906150e2565b6040517fcf479181000000000000000000000000000000000000000000000000000000008152600481019190915260248101829052604401610a6f565b61220273ffffffffffffffffffffffffffffffffffffffff84168383613f19565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f879f92dded0f26b83c3e00b12e0395dc72cfc3077343d1854ed6988edd1f90968360405161226191815260200190565b60405180910390a3505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166122db576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f90815260066020526040902054919050565b60607fffffffffffffffffffffffffffffffff00000000000000000000000000000000821661236b576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260056020526040902080546108f290614c3d565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612416576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260409020600101805461245490614c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461248090614c3d565b80156124cb5780601f106124a2576101008083540402835291602001916124cb565b820191905f5260205f20905b8154815290600101906020018083116124ae57829003601f168201915b505050505091505090565b60015473ffffffffffffffffffffffffffffffffffffffff163314612557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610a6f565b5f8054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b5f8061261286868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613fa692505050565b90925090505f6126266040602086886150f9565b61262f91615120565b905061263c816060615189565b6126479060406151a0565b8403612aeb575f61265a858701876151e9565b90505f5b82811015612ae4575f82828151811061267957612679614c8e565b6020908102919091018101518051604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831681860152338183015273ffffffffffffffffffffffffffffffffffffffff8b1660608201527fffffffffffffffffffff000000000000000000000000000000000000000000008a166080808301919091528251808303909101815260a090910182528051908501205f8181526009909552932054919350919060ff166127d5576040805133815273ffffffffffffffffffffffffffffffffffffffff8a1660208201527fffffffffffffffffffff000000000000000000000000000000000000000000008916918101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907feeeaa8bf618ff6d960c6cf5935e68384f066abcc8b95d0de91bd773c16ae3ae3906060015b60405180910390a2505050612adc565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600360209081526040909120549084015163ffffffff7c010000000000000000000000000000000000000000000000000000000090920482169116116128d4576020838101517fffffffffffffffffffffffffffffffff0000000000000000000000000000000084165f8181526003845260409081902054815163ffffffff94851681527c010000000000000000000000000000000000000000000000000000000090910490931693830193909352917fcf16f5f704f981fa2279afa1877dd1fdaa462a03a71ec51b9d3b2416a59a013e91016127c5565b604080518082018252848201517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815260208086015163ffffffff16818301527fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f908152600690915291822080549192918290612950906152d5565b91829055507fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f8181526003602090815260408083208751888401805163ffffffff9081167c01000000000000000000000000000000000000000000000000000000009081027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff94851617909455888752600486528487208888528652958490208a519151909616928302911690811790945590519283529394508492917f82584589cd7284d4503ed582275e22b2e8f459f9cf4170a7235844e367f966d5910160405180910390a460208086015160405163ffffffff90911681525f9183917f0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271910160405180910390a38085604001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f42604051612ace91815260200190565b60405180910390a350505050505b60010161265e565b5050611c1d565b5f612af88587018761530c565b90505f5b8151811015611454575f828281518110612b1857612b18614c8e565b6020908102919091018101518051604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831681860152338183015273ffffffffffffffffffffffffffffffffffffffff8b1660608201527fffffffffffffffffffff000000000000000000000000000000000000000000008a166080808301919091528251808303909101815260a090910182528051908501205f8181526009909552932054919350919060ff16612c74576040805133815273ffffffffffffffffffffffffffffffffffffffff8a1660208201527fffffffffffffffffffff000000000000000000000000000000000000000000008916918101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907feeeaa8bf618ff6d960c6cf5935e68384f066abcc8b95d0de91bd773c16ae3ae3906060015b60405180910390a2505050612e3d565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600560209081526040909120600101549084015163ffffffff918216911611612d37576020838101517fffffffffffffffffffffffffffffffff0000000000000000000000000000000084165f8181526005845260409081902060010154815163ffffffff9485168152931693830193909352917f51001b67094834cc084a0c1feb791cf84a481357aa66b924ba205d4cb56fd9819101612c64565b60408051808201825284820151815260208086015163ffffffff16818301527fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f90815260059091529190912081518291908190612d9790826154b1565b5060209182015160019190910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff92831617905590820151825160405191909216917fffffffffffffffffffffffffffffffff000000000000000000000000000000008616917f1dc1bef0b59d624eab3f0ec044781bb5b8594cd64f0ba09d789f5b51acab161491612e3091614581565b60405180910390a3505050505b600101612afc565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612eb2576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16919050565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612f7d576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600560205260409020805461245490614c3d565b335f90815260026020526040812054819081908190819060801b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000811661302d576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b69ffffffffffffffffffff87165f9081526004602090815260408083207fffffffffffffffffffffffffffffffff00000000000000000000000000000000949094168352929052205495967bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716967c0100000000000000000000000000000000000000000000000000000000900463ffffffff169550859450879350915050565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000811661313b576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f90815260086020908152604091829020805483518184028101840190945280845290918301828280156124cb57602002820191905f5260205f20905f905b825461010083900a900460ff1681526020600192830181810494850194909303909202910180841161319d579050505050505091505090565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116613243576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526005602052604090206001015463ffffffff16919050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166132ee576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f9283526004602090815260408085207fffffffffffffffffffffffffffffffff000000000000000000000000000000009093168552919052909120547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166133bb576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f9283526004602090815260408085207fffffffffffffffffffffffffffffffff0000000000000000000000000000000090931685529190529091205463ffffffff7c010000000000000000000000000000000000000000000000000000000090910416919050565b335f9081526007602052604090205460ff1661346e576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b805f5b8181101561352d575f84848381811061348c5761348c614c8e565b90506020020160208101906134a19190614777565b73ffffffffffffffffffffffffffffffffffffffff81165f8181526002602052604080822080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000808216909255915194955060809190911b9390841692917f4200186b7bc2d4f13f7888c5bbe9461d57da88705be86521f3d78be691ad1d2a91a35050600101613471565b50505050565b335f9081526007602052604090205460ff1661357d576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f5b81811015613893575f83838381811061359a5761359a614c8e565b90506020020160208101906135af919061451c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f9081526008602052604081206002015491925003613641576040517f8606a85b0000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166004820152602401610a6f565b5f5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860205260409020600201548110156137e6577fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f9081526008602052604081206002018054839081106136c3576136c3614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101613643565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260408120906138228282614319565b61382f600183015f61433b565b61383c600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008216907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25060010161357f565b505050565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083165f908152600860205260408120600281015460609281900361392d576040517f8606a85b0000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffff0000000000000000000000000000000087166004820152602401610a6f565b80851061399d57604080515f8082526020820190925290613993565b604080516060810182525f80825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816139495790505b5092505050613b34565b5f6139a885876151a0565b9050818111806139b6575084155b6139c057806139c2565b815b90506139ce86826155c8565b67ffffffffffffffff8111156139e6576139e6614ae6565b604051908082528060200260200182016040528015613a4e57816020015b604080516060810182525f80825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181613a045790505b5093505f5b8451811015613b2f5760028401613a6a88836151a0565b81548110613a7a57613a7a614c8e565b5f91825260209182902060408051606081018252600293909302909101805473ffffffffffffffffffffffffffffffffffffffff9081168452600190910154908116938301939093527401000000000000000000000000000000000000000090920460b01b7fffffffffffffffffffff0000000000000000000000000000000000000000000016918101919091528551869083908110613b1c57613b1c614c8e565b6020908102919091010152600101613a53565b505050505b9392505050565b613b43613e97565b73ffffffffffffffffffffffffffffffffffffffff8216613ba8576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610a6f565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526007602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915590519092917f93a3fa5993d2a54de369386625330cc6d73caee7fece4b3983cf299b264473fd91a35050565b613c2e613e97565b613c3781613fb7565b50565b335f90815260026020526040812054819081908190819060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116613caf576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526006602090815260408083205460039092529091205490967bffffffffffffffffffffffffffffffffffffffffffffffffffffffff821696507c010000000000000000000000000000000000000000000000000000000090910463ffffffff1694508493508692509050565b5f7fffffffffffffffffffffffffffffffff000000000000000000000000000000008216613d9b576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526005602052604090206001015463ffffffff1690565b5f80613de58360076140ab565b90507f20000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610801590613e7b57507f60000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821611155b15613e8f57613b34602060f883901c6155db565b505f92915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314613f17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610a6f565b565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261389390849061412a565b6040810151604a9091015160601c91565b3373ffffffffffffffffffffffffffffffffffffffff821603614036576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610a6f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092555f8054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6040517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831660208201525f9060300160405160208183030381529060405282815181106140fb576140fb614c8e565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016905092915050565b5f61414b73ffffffffffffffffffffffffffffffffffffffff8416836141be565b905080515f1415801561416f57508080602001905181019061416d91906155f4565b155b15613893576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610a6f565b6060613b3483835f845f808573ffffffffffffffffffffffffffffffffffffffff1684866040516141ef919061560f565b5f6040518083038185875af1925050503d805f8114614229576040519150601f19603f3d011682016040523d82523d5f602084013e61422e565b606091505b509150915061423e868383614248565b9695505050505050565b60608261425d57614258826142d7565b613b34565b8151158015614281575073ffffffffffffffffffffffffffffffffffffffff84163b155b156142d0576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610a6f565b5080613b34565b8051156142e75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5080545f8255601f0160209004905f5260205f2090810190613c379190614434565b50805461434790614c3d565b5f825580601f10614356575050565b601f0160209004905f5260205f2090810190613c379190614434565b5080545f8255600202905f5260205f2090810190613c379190614448565b828054828255905f5260205f2090601f01602090048101928215614424579160200282015f5b838211156143f657833560ff1683826101000a81548160ff021916908360ff16021790555092602001926001016020815f010492830192600103026143b6565b80156144225782816101000a81549060ff02191690556001016020815f010492830192600103026143f6565b505b50614430929150614434565b5090565b5b80821115614430575f8155600101614435565b5b808211156144305780547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810180547fffff000000000000000000000000000000000000000000000000000000000000169055600201614449565b5f602082840312156144b9575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114613b34575f80fd5b80357fffffffffffffffffffffffffffffffff0000000000000000000000000000000081168114614517575f80fd5b919050565b5f6020828403121561452c575f80fd5b613b34826144e8565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f613b346020830184614535565b5f8083601f8401126145a3575f80fd5b50813567ffffffffffffffff8111156145ba575f80fd5b6020830191508360208260051b85010111156145d4575f80fd5b9250929050565b5f805f80604085870312156145ee575f80fd5b843567ffffffffffffffff811115614604575f80fd5b61461087828801614593565b909550935050602085013567ffffffffffffffff81111561462f575f80fd5b61463b87828801614593565b95989497509550505050565b5f8083601f840112614657575f80fd5b50813567ffffffffffffffff81111561466e575f80fd5b6020830191508360206060830285010111156145d4575f80fd5b5f805f805f805f806080898b03121561469f575f80fd5b883567ffffffffffffffff8111156146b5575f80fd5b6146c18b828c01614593565b909950975050602089013567ffffffffffffffff8111156146e0575f80fd5b6146ec8b828c01614593565b909750955050604089013567ffffffffffffffff81111561470b575f80fd5b6147178b828c01614593565b909550935050606089013567ffffffffffffffff811115614736575f80fd5b6147428b828c01614647565b999c989b5096995094979396929594505050565b73ffffffffffffffffffffffffffffffffffffffff81168114613c37575f80fd5b5f60208284031215614787575f80fd5b8135613b3481614756565b5f805f805f80606087890312156147a7575f80fd5b863567ffffffffffffffff8111156147bd575f80fd5b6147c989828a01614593565b909750955050602087013567ffffffffffffffff8111156147e8575f80fd5b6147f489828a01614593565b909550935050604087013567ffffffffffffffff811115614813575f80fd5b61481f89828a01614647565b979a9699509497509295939492505050565b602080825282518282018190525f918401906040840190835b8181101561486b57835160ff1683526020938401939092019160010161484a565b509095945050505050565b5f805f60608486031215614888575f80fd5b833561489381614756565b925060208401356148a381614756565b929592945050506040919091013590565b5f8083601f8401126148c4575f80fd5b50813567ffffffffffffffff8111156148db575f80fd5b6020830191508360208285010111156145d4575f80fd5b5f805f8060408587031215614905575f80fd5b843567ffffffffffffffff81111561491b575f80fd5b614927878288016148b4565b909550935050602085013567ffffffffffffffff811115614946575f80fd5b61463b878288016148b4565b5f60208284031215614962575f80fd5b813569ffffffffffffffffffff81168114613b34575f80fd5b5f6020828403121561498b575f80fd5b5035919050565b5f80602083850312156149a3575f80fd5b823567ffffffffffffffff8111156149b9575f80fd5b6149c585828601614593565b90969095509350505050565b5f805f606084860312156149e3575f80fd5b6149ec846144e8565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b8181101561486b57835173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff60208201511660208501527fffffffffffffffffffff00000000000000000000000000000000000000000000604082015116604085015250606083019250602084019350600181019050614a1a565b8015158114613c37575f80fd5b5f8060408385031215614ac0575f80fd5b8235614acb81614756565b91506020830135614adb81614aa2565b809150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614b3657614b36614ae6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614b8357614b83614ae6565b604052919050565b80357fffffffffffffffffffff0000000000000000000000000000000000000000000081168114614517575f80fd5b5f60608284031215614bca575f80fd5b614bd2614b13565b90508135614bdf81614756565b81526020820135614bef81614756565b6020820152614c0060408301614b8b565b604082015292915050565b5f8060808385031215614c1c575f80fd5b614c25836144e8565b9150614c348460208501614bba565b90509250929050565b600181811c90821680614c5157607f821691505b602082108103614c88577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60608284031215614ccb575f80fd5b613b348383614bba565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d08575f80fd5b83018035915067ffffffffffffffff821115614d22575f80fd5b6020019150600581901b36038213156145d4575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d6c575f80fd5b83018035915067ffffffffffffffff821115614d86575f80fd5b6020019150368190038213156145d4575f80fd5b601f82111561389357805f5260205f20601f840160051c81016020851015614dbf5750805b601f840160051c820191505b81811015614dde575f8155600101614dcb565b5050505050565b67ffffffffffffffff831115614dfd57614dfd614ae6565b614e1183614e0b8354614c3d565b83614d9a565b5f601f841160018114614e61575f8515614e2b5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614dde565b5f838152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08716915b82811015614eae5786850135825560209485019460019092019101614e8e565b5086821015614ee9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b8183526020830192505f815f5b84811015614fe9578135614f6281614756565b73ffffffffffffffffffffffffffffffffffffffff1686526020820135614f8881614756565b73ffffffffffffffffffffffffffffffffffffffff1660208701527fffffffffffffffffffff00000000000000000000000000000000000000000000614fd060408401614b8b565b1660408701526060958601959190910190600101614f4f565b5093949350505050565b606080825281018690525f8760808301825b8981101561503357823560ff811680821461501e575f80fd5b83525060209283019290910190600101615005565b50838103602085015261504781888a614efb565b915050828103604084015261505d818587614f42565b9998505050505050505050565b60ff86168152606060208201525f615086606083018688614efb565b8281036040840152615099818587614f42565b98975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f6150d96060830184614535565b95945050505050565b5f602082840312156150f2575f80fd5b5051919050565b5f8085851115615107575f80fd5b83861115615113575f80fd5b5050820193919092039150565b80356020831015610853577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820281158282048414176108535761085361515c565b808201808211156108535761085361515c565b5f67ffffffffffffffff8211156151cc576151cc614ae6565b5060051b60200190565b803563ffffffff81168114614517575f80fd5b5f602082840312156151f9575f80fd5b813567ffffffffffffffff81111561520f575f80fd5b8201601f8101841361521f575f80fd5b803561523261522d826151b3565b614b3c565b80828252602082019150602060608402850101925086831115615253575f80fd5b6020840193505b8284101561423e5760608488031215615271575f80fd5b615279614b13565b84358152615289602086016151d6565b602082015260408501357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146152bc575f80fd5b604082015282526060939093019260209091019061525a565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036153055761530561515c565b5060010190565b5f6020828403121561531c575f80fd5b813567ffffffffffffffff811115615332575f80fd5b8201601f81018413615342575f80fd5b803561535061522d826151b3565b8082825260208201915060208360051b850101925086831115615371575f80fd5b602084015b838110156154a657803567ffffffffffffffff811115615394575f80fd5b85016060818a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156153c7575f80fd5b6153cf614b13565b602082013581526153e2604083016151d6565b6020820152606082013567ffffffffffffffff811115615400575f80fd5b60208184010192505089601f830112615417575f80fd5b813567ffffffffffffffff81111561543157615431614ae6565b61546260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b3c565b8181528b6020838601011115615476575f80fd5b816020850160208301375f6020838301015280604084015250508085525050602083019250602081019050615376565b509695505050505050565b815167ffffffffffffffff8111156154cb576154cb614ae6565b6154df816154d98454614c3d565b84614d9a565b6020601f821160018114615530575f83156154fa5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455614dde565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b8281101561557d578785015182556020948501946001909201910161555d565b50848210156155b957868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b818103818111156108535761085361515c565b60ff82811682821603908111156108535761085361515c565b5f60208284031215615604575f80fd5b8151613b3481614aa2565b5f82518060208501845e5f92019182525091905056fea164736f6c634300081a000a

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610283575f3560e01c806379ba509711610157578063b5ab58dc116100d2578063ec52b1f511610088578063feaf968c1161006e578063feaf968c146105ff578063feb5d17214610607578063ff25dbc8146106ca575f80fd5b8063ec52b1f5146105d9578063f2fde38b146105ec575f80fd5b8063be4f0a9f116100b8578063be4f0a9f14610593578063cdd25100146105a6578063d143dcd9146105b9575f80fd5b8063b5ab58dc1461056d578063b633620c14610580575f80fd5b80639198274f116101275780639a6fc8f51161010d5780639a6fc8f51461054a5780639d91348d1461055d578063a3d610cc14610565575f80fd5b80639198274f146104d95780639608e18f146104e1575f80fd5b806379ba50971461048f578063805f2132146104975780638205bf6a146104aa5780638da5cb5b146104b2575f80fd5b80634533dc98116102015780635f25452b116101b7578063668a0f021161019d578063668a0f021461046c5780636a36e494146104745780637284e41614610487575f80fd5b80635f25452b1461040f5780635f3e849f14610459575f80fd5b806350d25bcd116101e757806350d25bcd146103ec57806354fd4d50146103f4578063557a33c2146103fc575f80fd5b80634533dc98146103b957806347381b08146103cc575f80fd5b8063297dbf561161025657806335f611221161023c57806335f611221461035b5780633a0449741461036e57806343d5ba50146103a6575f80fd5b8063297dbf561461032c578063313ce56714610341575f80fd5b806301ffc9a71461028757806302ccb3ae146102af578063181f5a77146102cf5780631bb1610c1461030b575b5f80fd5b61029a6102953660046144a9565b6106dd565b60405190151581526020015b60405180910390f35b6102c26102bd36600461451c565b610859565b6040516102a69190614581565b6102c26040518060400160405280601481526020017f446174614665656473436163686520312e302e3000000000000000000000000081525081565b61031e61031936600461451c565b610975565b6040519081526020016102a6565b61033f61033a3660046145db565b610a29565b005b610349610c24565b60405160ff90911681526020016102a6565b61033f610369366004614688565b610ca0565b61029a61037c366004614777565b73ffffffffffffffffffffffffffffffffffffffff165f9081526007602052604090205460ff1690565b6103496103b436600461451c565b61145f565b61033f6103c7366004614792565b6114c2565b6103df6103da36600461451c565b611c26565b6040516102a69190614831565b61031e611d1c565b61031e600781565b61031e61040a36600461451c565b611ddc565b61042261041d36600461451c565b611e88565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016102a6565b61033f610467366004614876565b611f7a565b61031e61226e565b6102c261048236600461451c565b612310565b6102c26123a6565b61033f6124d6565b61033f6104a53660046148f2565b6125d2565b61031e612e45565b5f5460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102a6565b6102c2612f0d565b6105196104ef366004614777565b73ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205460801b90565b6040517fffffffffffffffffffffffffffffffff0000000000000000000000000000000090911681526020016102a6565b610422610558366004614952565b612fb8565b6103df6130cb565b61031e6131d6565b61031e61057b36600461497b565b613281565b61031e61058e36600461497b565b61334e565b61033f6105a1366004614992565b613424565b61033f6105b4366004614992565b613533565b6105cc6105c73660046149d1565b613898565b6040516102a69190614a01565b61033f6105e7366004614aaf565b613b3b565b61033f6105fa366004614777565b613c26565b610422613c3a565b61029a610615366004614c0b565b805160208083015160409384015184517fffffffffffffffffffffffffffffffff00000000000000000000000000000000969096168684015273ffffffffffffffffffffffffffffffffffffffff93841686860152921660608501527fffffffffffffffffffff000000000000000000000000000000000000000000009091166080808501919091528251808503909101815260a090930182528251928101929092205f908152600990925290205460ff1690565b61031e6106d836600461451c565b613d41565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167fcce8054600000000000000000000000000000000000000000000000000000000148061076f57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b806107bb57507fffffffff0000000000000000000000000000000000000000000000000000000082167f805f213200000000000000000000000000000000000000000000000000000000145b8061080757507fffffffff0000000000000000000000000000000000000000000000000000000082167f5f3e849f00000000000000000000000000000000000000000000000000000000145b8061085357507fffffffff0000000000000000000000000000000000000000000000000000000082167f181f5a7700000000000000000000000000000000000000000000000000000000145b92915050565b60607fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166108b4576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260086020526040902060010180546108f290614c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461091e90614c3d565b80156109695780601f1061094057610100808354040283529160200191610969565b820191905f5260205f20905b81548152906001019060200180831161094c57829003601f168201915b50505050509050919050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166109cf576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1690565b335f9081526007602052604090205460ff16610a78576040517fd86ad9cf0000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b82818114610ab2576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b81811015610c1c57838382818110610ace57610ace614c8e565b9050602002016020810190610ae3919061451c565b60025f888885818110610af857610af8614c8e565b9050602002016020810190610b0d9190614777565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f2080547fffffffffffffffffffffffffffffffff000000000000000000000000000000001660809290921c919091179055838382818110610b7457610b74614c8e565b9050602002016020810190610b89919061451c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016868683818110610bbd57610bbd614c8e565b9050602002016020810190610bd29190614777565b73ffffffffffffffffffffffffffffffffffffffff167ff31b9e58190970ef07c23d0ba78c358eb3b416e829ef484b29b9993a6b1b285a60405160405180910390a3600101610ab4565b505050505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116610c91576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b610c9a81613dd8565b91505090565b335f9081526007602052604090205460ff16610cea576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b801580610cf5575086155b15610d2c576040517f60e8b63a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8685141580610d3b5750868314155b15610d72576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b87811015611454575f898983818110610d8f57610d8f614c8e565b9050602002016020810190610da4919061451c565b90507fffffffffffffffffffffffffffffffff000000000000000000000000000000008116610dff576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260409020600281015415611025575f5b6002820154811015610f80575f826002018281548110610e5d57610e5d614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008d168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101610e3b565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260086020526040812090610fbc8282614319565b610fc9600183015f61433b565b610fd6600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25b5f5b8481101561133c575f86868381811061104257611042614c8e565b9050606002018036038101906110589190614cbb565b9050845f036111c057805173ffffffffffffffffffffffffffffffffffffffff166110ca5780516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b602081015173ffffffffffffffffffffffffffffffffffffffff166111395760208101516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b60408101517fffffffffffffffffffff00000000000000000000000000000000000000000000166111c05760408082015190517f114988d50000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff000000000000000000000000000000000000000000009091166004820152602401610a6f565b8051602080830180516040808601805182517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015273ffffffffffffffffffffffffffffffffffffffff9788168185015293871660608501527fffffffffffffffffffff00000000000000000000000000000000000000000000166080808501919091528251808503909101815260a090930182528251928501929092205f9081526009855290812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091556002898101805480840182559084529590922096519490910290950180549385167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317835590519184018054915160b01c74010000000000000000000000000000000000000000027fffff000000000000000000000000000000000000000000000000000000000000909216929093169190911717905501611027565b5086868481811061134f5761134f614c8e565b90506020028101906113619190614cd5565b61136c918391614390565b5088888481811061137f5761137f614c8e565b90506020028101906113919190614d39565b60018301916113a1919083614de5565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082167fdfebe0878c5611549f54908260ca12271c7ff3f0ebae0c1de47732612403869e8888868181106113f8576113f8614c8e565b905060200281019061140a9190614cd5565b8c8c8881811061141c5761141c614c8e565b905060200281019061142e9190614d39565b8a8a60405161144296959493929190614ff3565b60405180910390a25050600101610d74565b505050505050505050565b5f7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166114b9576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61085382613dd8565b335f9081526007602052604090205460ff1661150c576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b801580611517575084155b1561154e576040517f60e8b63a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b848314611587576040517fa24a13a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b85811015611c1d575f8787838181106115a4576115a4614c8e565b90506020020160208101906115b9919061451c565b90507fffffffffffffffffffffffffffffffff000000000000000000000000000000008116611614576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f90815260086020526040902060028101541561183a575f5b6002820154811015611795575f82600201828154811061167257611672614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008d168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101611650565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860205260408120906117d18282614319565b6117de600183015f61433b565b6117eb600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25b5f5b84811015611b51575f86868381811061185757611857614c8e565b90506060020180360381019061186d9190614cbb565b9050845f036119d557805173ffffffffffffffffffffffffffffffffffffffff166118df5780516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b602081015173ffffffffffffffffffffffffffffffffffffffff1661194e5760208101516040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610a6f565b60408101517fffffffffffffffffffff00000000000000000000000000000000000000000000166119d55760408082015190517f114988d50000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff000000000000000000000000000000000000000000009091166004820152602401610a6f565b8051602080830180516040808601805182517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015273ffffffffffffffffffffffffffffffffffffffff9788168185015293871660608501527fffffffffffffffffffff00000000000000000000000000000000000000000000166080808501919091528251808503909101815260a090930182528251928501929092205f9081526009855290812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091556002898101805480840182559084529590922096519490910290950180549385167fffffffffffffffffffffffff000000000000000000000000000000000000000090941693909317835590519184018054915160b01c74010000000000000000000000000000000000000000027fffff00000000000000000000000000000000000000000000000000000000000090921692909316919091171790550161183c565b50868684818110611b6457611b64614c8e565b9050602002810190611b769190614d39565b6001830191611b86919083614de5565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082167f2dec0e9ffbb18c6499fc8bee8b9c35f765e76d9dbd436f25dd00a80de267ac0d611bd484613dd8565b898987818110611be657611be6614c8e565b9050602002810190611bf89190614d39565b8989604051611c0b95949392919061506a565b60405180910390a25050600101611589565b50505050505050565b60607fffffffffffffffffffffffffffffffff000000000000000000000000000000008216611c81576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860209081526040918290208054835181840281018401909452808452909183018282801561096957602002820191905f5260205f20905f905b825461010083900a900460ff16815260206001928301818104948501949093039092029101808411611ce3575094979650505050505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116611d89576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b5f7fffffffffffffffffffffffffffffffff000000000000000000000000000000008216611e36576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b5f808080807fffffffffffffffffffffffffffffffff000000000000000000000000000000008616611ee6576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050507fffffffffffffffffffffffffffffffff00000000000000000000000000000000919091165f9081526006602090815260408083205460039092529091205490927bffffffffffffffffffffffffffffffffffffffffffffffffffffffff821692507c010000000000000000000000000000000000000000000000000000000090910463ffffffff169081908490565b611f82613e97565b73ffffffffffffffffffffffffffffffffffffffff83166120855747811115611fe0576040517fcf47918100000000000000000000000000000000000000000000000000000000815247600482015260248101829052604401610a6f565b5f808373ffffffffffffffffffffffffffffffffffffffff16836040515f6040518083038185875af1925050503d805f8114612037576040519150601f19603f3d011682016040523d82523d5f602084013e61203c565b606091505b50915091508161207e578383826040517fc50febed000000000000000000000000000000000000000000000000000000008152600401610a6f939291906150a5565b5050612202565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156120ed573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061211191906150e2565b8111156121e1576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015612180573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121a491906150e2565b6040517fcf479181000000000000000000000000000000000000000000000000000000008152600481019190915260248101829052604401610a6f565b61220273ffffffffffffffffffffffffffffffffffffffff84168383613f19565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f879f92dded0f26b83c3e00b12e0395dc72cfc3077343d1854ed6988edd1f90968360405161226191815260200190565b60405180910390a3505050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166122db576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f90815260066020526040902054919050565b60607fffffffffffffffffffffffffffffffff00000000000000000000000000000000821661236b576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f90815260056020526040902080546108f290614c3d565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612416576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260409020600101805461245490614c3d565b80601f016020809104026020016040519081016040528092919081815260200182805461248090614c3d565b80156124cb5780601f106124a2576101008083540402835291602001916124cb565b820191905f5260205f20905b8154815290600101906020018083116124ae57829003601f168201915b505050505091505090565b60015473ffffffffffffffffffffffffffffffffffffffff163314612557576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610a6f565b5f8054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b5f8061261286868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250613fa692505050565b90925090505f6126266040602086886150f9565b61262f91615120565b905061263c816060615189565b6126479060406151a0565b8403612aeb575f61265a858701876151e9565b90505f5b82811015612ae4575f82828151811061267957612679614c8e565b6020908102919091018101518051604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831681860152338183015273ffffffffffffffffffffffffffffffffffffffff8b1660608201527fffffffffffffffffffff000000000000000000000000000000000000000000008a166080808301919091528251808303909101815260a090910182528051908501205f8181526009909552932054919350919060ff166127d5576040805133815273ffffffffffffffffffffffffffffffffffffffff8a1660208201527fffffffffffffffffffff000000000000000000000000000000000000000000008916918101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907feeeaa8bf618ff6d960c6cf5935e68384f066abcc8b95d0de91bd773c16ae3ae3906060015b60405180910390a2505050612adc565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600360209081526040909120549084015163ffffffff7c010000000000000000000000000000000000000000000000000000000090920482169116116128d4576020838101517fffffffffffffffffffffffffffffffff0000000000000000000000000000000084165f8181526003845260409081902054815163ffffffff94851681527c010000000000000000000000000000000000000000000000000000000090910490931693830193909352917fcf16f5f704f981fa2279afa1877dd1fdaa462a03a71ec51b9d3b2416a59a013e91016127c5565b604080518082018252848201517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815260208086015163ffffffff16818301527fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f908152600690915291822080549192918290612950906152d5565b91829055507fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f8181526003602090815260408083208751888401805163ffffffff9081167c01000000000000000000000000000000000000000000000000000000009081027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff94851617909455888752600486528487208888528652958490208a519151909616928302911690811790945590519283529394508492917f82584589cd7284d4503ed582275e22b2e8f459f9cf4170a7235844e367f966d5910160405180910390a460208086015160405163ffffffff90911681525f9183917f0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271910160405180910390a38085604001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f42604051612ace91815260200190565b60405180910390a350505050505b60010161265e565b5050611c1d565b5f612af88587018761530c565b90505f5b8151811015611454575f828281518110612b1857612b18614c8e565b6020908102919091018101518051604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831681860152338183015273ffffffffffffffffffffffffffffffffffffffff8b1660608201527fffffffffffffffffffff000000000000000000000000000000000000000000008a166080808301919091528251808303909101815260a090910182528051908501205f8181526009909552932054919350919060ff16612c74576040805133815273ffffffffffffffffffffffffffffffffffffffff8a1660208201527fffffffffffffffffffff000000000000000000000000000000000000000000008916918101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008316907feeeaa8bf618ff6d960c6cf5935e68384f066abcc8b95d0de91bd773c16ae3ae3906060015b60405180910390a2505050612e3d565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600560209081526040909120600101549084015163ffffffff918216911611612d37576020838101517fffffffffffffffffffffffffffffffff0000000000000000000000000000000084165f8181526005845260409081902060010154815163ffffffff9485168152931693830193909352917f51001b67094834cc084a0c1feb791cf84a481357aa66b924ba205d4cb56fd9819101612c64565b60408051808201825284820151815260208086015163ffffffff16818301527fffffffffffffffffffffffffffffffff0000000000000000000000000000000085165f90815260059091529190912081518291908190612d9790826154b1565b5060209182015160019190910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff92831617905590820151825160405191909216917fffffffffffffffffffffffffffffffff000000000000000000000000000000008616917f1dc1bef0b59d624eab3f0ec044781bb5b8594cd64f0ba09d789f5b51acab161491612e3091614581565b60405180910390a3505050505b600101612afc565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612eb2576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f908152600360205260409020547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16919050565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116612f7d576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600560205260409020805461245490614c3d565b335f90815260026020526040812054819081908190819060801b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000811661302d576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b69ffffffffffffffffffff87165f9081526004602090815260408083207fffffffffffffffffffffffffffffffff00000000000000000000000000000000949094168352929052205495967bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8716967c0100000000000000000000000000000000000000000000000000000000900463ffffffff169550859450879350915050565b335f9081526002602052604090205460609060801b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000811661313b576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f90815260086020908152604091829020805483518184028101840190945280845290918301828280156124cb57602002820191905f5260205f20905f905b825461010083900a900460ff1681526020600192830181810494850194909303909202910180841161319d579050505050505091505090565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116613243576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526005602052604090206001015463ffffffff16919050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166132ee576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f9283526004602090815260408085207fffffffffffffffffffffffffffffffff000000000000000000000000000000009093168552919052909120547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b335f9081526002602052604081205460801b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166133bb576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f9283526004602090815260408085207fffffffffffffffffffffffffffffffff0000000000000000000000000000000090931685529190529091205463ffffffff7c010000000000000000000000000000000000000000000000000000000090910416919050565b335f9081526007602052604090205460ff1661346e576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b805f5b8181101561352d575f84848381811061348c5761348c614c8e565b90506020020160208101906134a19190614777565b73ffffffffffffffffffffffffffffffffffffffff81165f8181526002602052604080822080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000808216909255915194955060809190911b9390841692917f4200186b7bc2d4f13f7888c5bbe9461d57da88705be86521f3d78be691ad1d2a91a35050600101613471565b50505050565b335f9081526007602052604090205460ff1661357d576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b5f5b81811015613893575f83838381811061359a5761359a614c8e565b90506020020160208101906135af919061451c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f9081526008602052604081206002015491925003613641576040517f8606a85b0000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166004820152602401610a6f565b5f5b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f908152600860205260409020600201548110156137e6577fffffffffffffffffffffffffffffffff0000000000000000000000000000000082165f9081526008602052604081206002018054839081106136c3576136c3614c8e565b5f91825260208083206040805160608082018352600295909502909201805473ffffffffffffffffffffffffffffffffffffffff9081168085526001909201549081168486018190527401000000000000000000000000000000000000000090910460b01b7fffffffffffffffffffff000000000000000000000000000000000000000000001684840181905283517fffffffffffffffffffffffffffffffff000000000000000000000000000000008c168188015280850193909352958201526080808201959095528151808203909501855260a0019052825192909101919091209092505f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555050600101613643565b507fffffffffffffffffffffffffffffffff0000000000000000000000000000000081165f908152600860205260408120906138228282614319565b61382f600183015f61433b565b61383c600283015f614372565b50506040517fffffffffffffffffffffffffffffffff000000000000000000000000000000008216907f871bcdef10dee59b87f17bab788b72faa8dfe1a9cc5bdc45c3baf4c18fa33910905f90a25060010161357f565b505050565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083165f908152600860205260408120600281015460609281900361392d576040517f8606a85b0000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffff0000000000000000000000000000000087166004820152602401610a6f565b80851061399d57604080515f8082526020820190925290613993565b604080516060810182525f80825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816139495790505b5092505050613b34565b5f6139a885876151a0565b9050818111806139b6575084155b6139c057806139c2565b815b90506139ce86826155c8565b67ffffffffffffffff8111156139e6576139e6614ae6565b604051908082528060200260200182016040528015613a4e57816020015b604080516060810182525f80825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181613a045790505b5093505f5b8451811015613b2f5760028401613a6a88836151a0565b81548110613a7a57613a7a614c8e565b5f91825260209182902060408051606081018252600293909302909101805473ffffffffffffffffffffffffffffffffffffffff9081168452600190910154908116938301939093527401000000000000000000000000000000000000000090920460b01b7fffffffffffffffffffff0000000000000000000000000000000000000000000016918101919091528551869083908110613b1c57613b1c614c8e565b6020908102919091010152600101613a53565b505050505b9392505050565b613b43613e97565b73ffffffffffffffffffffffffffffffffffffffff8216613ba8576040517f8e4c8aa600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610a6f565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526007602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915590519092917f93a3fa5993d2a54de369386625330cc6d73caee7fece4b3983cf299b264473fd91a35050565b613c2e613e97565b613c3781613fb7565b50565b335f90815260026020526040812054819081908190819060801b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116613caf576040517f718b09d0000000000000000000000000000000000000000000000000000000008152336004820152602401610a6f565b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526006602090815260408083205460039092529091205490967bffffffffffffffffffffffffffffffffffffffffffffffffffffffff821696507c010000000000000000000000000000000000000000000000000000000090910463ffffffff1694508493508692509050565b5f7fffffffffffffffffffffffffffffffff000000000000000000000000000000008216613d9b576040517f0760371200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fffffffffffffffffffffffffffffffff00000000000000000000000000000000165f9081526005602052604090206001015463ffffffff1690565b5f80613de58360076140ab565b90507f20000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821610801590613e7b57507f60000000000000000000000000000000000000000000000000000000000000007fff00000000000000000000000000000000000000000000000000000000000000821611155b15613e8f57613b34602060f883901c6155db565b505f92915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314613f17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610a6f565b565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261389390849061412a565b6040810151604a9091015160601c91565b3373ffffffffffffffffffffffffffffffffffffffff821603614036576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610a6f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092555f8054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6040517fffffffffffffffffffffffffffffffff00000000000000000000000000000000831660208201525f9060300160405160208183030381529060405282815181106140fb576140fb614c8e565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016905092915050565b5f61414b73ffffffffffffffffffffffffffffffffffffffff8416836141be565b905080515f1415801561416f57508080602001905181019061416d91906155f4565b155b15613893576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610a6f565b6060613b3483835f845f808573ffffffffffffffffffffffffffffffffffffffff1684866040516141ef919061560f565b5f6040518083038185875af1925050503d805f8114614229576040519150601f19603f3d011682016040523d82523d5f602084013e61422e565b606091505b509150915061423e868383614248565b9695505050505050565b60608261425d57614258826142d7565b613b34565b8151158015614281575073ffffffffffffffffffffffffffffffffffffffff84163b155b156142d0576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610a6f565b5080613b34565b8051156142e75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5080545f8255601f0160209004905f5260205f2090810190613c379190614434565b50805461434790614c3d565b5f825580601f10614356575050565b601f0160209004905f5260205f2090810190613c379190614434565b5080545f8255600202905f5260205f2090810190613c379190614448565b828054828255905f5260205f2090601f01602090048101928215614424579160200282015f5b838211156143f657833560ff1683826101000a81548160ff021916908360ff16021790555092602001926001016020815f010492830192600103026143b6565b80156144225782816101000a81549060ff02191690556001016020815f010492830192600103026143f6565b505b50614430929150614434565b5090565b5b80821115614430575f8155600101614435565b5b808211156144305780547fffffffffffffffffffffffff00000000000000000000000000000000000000001681556001810180547fffff000000000000000000000000000000000000000000000000000000000000169055600201614449565b5f602082840312156144b9575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114613b34575f80fd5b80357fffffffffffffffffffffffffffffffff0000000000000000000000000000000081168114614517575f80fd5b919050565b5f6020828403121561452c575f80fd5b613b34826144e8565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f613b346020830184614535565b5f8083601f8401126145a3575f80fd5b50813567ffffffffffffffff8111156145ba575f80fd5b6020830191508360208260051b85010111156145d4575f80fd5b9250929050565b5f805f80604085870312156145ee575f80fd5b843567ffffffffffffffff811115614604575f80fd5b61461087828801614593565b909550935050602085013567ffffffffffffffff81111561462f575f80fd5b61463b87828801614593565b95989497509550505050565b5f8083601f840112614657575f80fd5b50813567ffffffffffffffff81111561466e575f80fd5b6020830191508360206060830285010111156145d4575f80fd5b5f805f805f805f806080898b03121561469f575f80fd5b883567ffffffffffffffff8111156146b5575f80fd5b6146c18b828c01614593565b909950975050602089013567ffffffffffffffff8111156146e0575f80fd5b6146ec8b828c01614593565b909750955050604089013567ffffffffffffffff81111561470b575f80fd5b6147178b828c01614593565b909550935050606089013567ffffffffffffffff811115614736575f80fd5b6147428b828c01614647565b999c989b5096995094979396929594505050565b73ffffffffffffffffffffffffffffffffffffffff81168114613c37575f80fd5b5f60208284031215614787575f80fd5b8135613b3481614756565b5f805f805f80606087890312156147a7575f80fd5b863567ffffffffffffffff8111156147bd575f80fd5b6147c989828a01614593565b909750955050602087013567ffffffffffffffff8111156147e8575f80fd5b6147f489828a01614593565b909550935050604087013567ffffffffffffffff811115614813575f80fd5b61481f89828a01614647565b979a9699509497509295939492505050565b602080825282518282018190525f918401906040840190835b8181101561486b57835160ff1683526020938401939092019160010161484a565b509095945050505050565b5f805f60608486031215614888575f80fd5b833561489381614756565b925060208401356148a381614756565b929592945050506040919091013590565b5f8083601f8401126148c4575f80fd5b50813567ffffffffffffffff8111156148db575f80fd5b6020830191508360208285010111156145d4575f80fd5b5f805f8060408587031215614905575f80fd5b843567ffffffffffffffff81111561491b575f80fd5b614927878288016148b4565b909550935050602085013567ffffffffffffffff811115614946575f80fd5b61463b878288016148b4565b5f60208284031215614962575f80fd5b813569ffffffffffffffffffff81168114613b34575f80fd5b5f6020828403121561498b575f80fd5b5035919050565b5f80602083850312156149a3575f80fd5b823567ffffffffffffffff8111156149b9575f80fd5b6149c585828601614593565b90969095509350505050565b5f805f606084860312156149e3575f80fd5b6149ec846144e8565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b8181101561486b57835173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff60208201511660208501527fffffffffffffffffffff00000000000000000000000000000000000000000000604082015116604085015250606083019250602084019350600181019050614a1a565b8015158114613c37575f80fd5b5f8060408385031215614ac0575f80fd5b8235614acb81614756565b91506020830135614adb81614aa2565b809150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614b3657614b36614ae6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614b8357614b83614ae6565b604052919050565b80357fffffffffffffffffffff0000000000000000000000000000000000000000000081168114614517575f80fd5b5f60608284031215614bca575f80fd5b614bd2614b13565b90508135614bdf81614756565b81526020820135614bef81614756565b6020820152614c0060408301614b8b565b604082015292915050565b5f8060808385031215614c1c575f80fd5b614c25836144e8565b9150614c348460208501614bba565b90509250929050565b600181811c90821680614c5157607f821691505b602082108103614c88577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60608284031215614ccb575f80fd5b613b348383614bba565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d08575f80fd5b83018035915067ffffffffffffffff821115614d22575f80fd5b6020019150600581901b36038213156145d4575f80fd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614d6c575f80fd5b83018035915067ffffffffffffffff821115614d86575f80fd5b6020019150368190038213156145d4575f80fd5b601f82111561389357805f5260205f20601f840160051c81016020851015614dbf5750805b601f840160051c820191505b81811015614dde575f8155600101614dcb565b5050505050565b67ffffffffffffffff831115614dfd57614dfd614ae6565b614e1183614e0b8354614c3d565b83614d9a565b5f601f841160018114614e61575f8515614e2b5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614dde565b5f838152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08716915b82811015614eae5786850135825560209485019460019092019101614e8e565b5086821015614ee9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b8183526020830192505f815f5b84811015614fe9578135614f6281614756565b73ffffffffffffffffffffffffffffffffffffffff1686526020820135614f8881614756565b73ffffffffffffffffffffffffffffffffffffffff1660208701527fffffffffffffffffffff00000000000000000000000000000000000000000000614fd060408401614b8b565b1660408701526060958601959190910190600101614f4f565b5093949350505050565b606080825281018690525f8760808301825b8981101561503357823560ff811680821461501e575f80fd5b83525060209283019290910190600101615005565b50838103602085015261504781888a614efb565b915050828103604084015261505d818587614f42565b9998505050505050505050565b60ff86168152606060208201525f615086606083018688614efb565b8281036040840152615099818587614f42565b98975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201525f6150d96060830184614535565b95945050505050565b5f602082840312156150f2575f80fd5b5051919050565b5f8085851115615107575f80fd5b83861115615113575f80fd5b5050820193919092039150565b80356020831015610853577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820281158282048414176108535761085361515c565b808201808211156108535761085361515c565b5f67ffffffffffffffff8211156151cc576151cc614ae6565b5060051b60200190565b803563ffffffff81168114614517575f80fd5b5f602082840312156151f9575f80fd5b813567ffffffffffffffff81111561520f575f80fd5b8201601f8101841361521f575f80fd5b803561523261522d826151b3565b614b3c565b80828252602082019150602060608402850101925086831115615253575f80fd5b6020840193505b8284101561423e5760608488031215615271575f80fd5b615279614b13565b84358152615289602086016151d6565b602082015260408501357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146152bc575f80fd5b604082015282526060939093019260209091019061525a565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036153055761530561515c565b5060010190565b5f6020828403121561531c575f80fd5b813567ffffffffffffffff811115615332575f80fd5b8201601f81018413615342575f80fd5b803561535061522d826151b3565b8082825260208201915060208360051b850101925086831115615371575f80fd5b602084015b838110156154a657803567ffffffffffffffff811115615394575f80fd5b85016060818a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156153c7575f80fd5b6153cf614b13565b602082013581526153e2604083016151d6565b6020820152606082013567ffffffffffffffff811115615400575f80fd5b60208184010192505089601f830112615417575f80fd5b813567ffffffffffffffff81111561543157615431614ae6565b61546260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b3c565b8181528b6020838601011115615476575f80fd5b816020850160208301375f6020838301015280604084015250508085525050602083019250602081019050615376565b509695505050505050565b815167ffffffffffffffff8111156154cb576154cb614ae6565b6154df816154d98454614c3d565b84614d9a565b6020601f821160018114615530575f83156154fa5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455614dde565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b8281101561557d578785015182556020948501946001909201910161555d565b50848210156155b957868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b818103818111156108535761085361515c565b60ff82811682821603908111156108535761085361515c565b5f60208284031215615604575f80fd5b8151613b3481614aa2565b5f82518060208501845e5f92019182525091905056fea164736f6c634300081a000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
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  ]

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.