{"file_path":"contracts/xManager/OndoRateLimiter.sol","creation_status":"success","source_code":"//SPDX-License-Identifier: MIT\n/*\n      ▄▄█████████▄\n   ╓██▀└ ,╓▄▄▄, '▀██▄\n  ██▀ ▄██▀▀╙╙▀▀██▄ └██µ           ,,       ,,      ,     ,,,            ,,,\n ██ ,██¬ ▄████▄  ▀█▄ ╙█▄      ▄███▀▀███▄   ███▄    ██  ███▀▀▀███▄    ▄███▀▀███,\n██  ██ ╒█▀'   ╙█▌ ╙█▌ ██     ▐██      ███  █████,  ██  ██▌    └██▌  ██▌     └██▌\n██ ▐█▌ ██      ╟█  █▌ ╟█     ██▌      ▐██  ██ └███ ██  ██▌     ╟██ j██       ╟██\n╟█  ██ ╙██    ▄█▀ ▐█▌ ██     ╙██      ██▌  ██   ╙████  ██▌    ▄██▀  ██▌     ,██▀\n ██ \"██, ╙▀▀███████████⌐      ╙████████▀   ██     ╙██  ███████▀▀     ╙███████▀`\n  ██▄ ╙▀██▄▄▄▄▄,,,                ¬─                                    '─¬\n   ╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀\n      ╙▀▀██████R⌐\n */\npragma solidity 0.8.16;\n\nimport \"contracts/xManager/interfaces/IOndoRateLimiter.sol\";\nimport \"contracts/external/openzeppelin/contracts/access/AccessControlEnumerable.sol\";\n\n/**\n * @title  OndoRateLimiter\n * @author Ondo Finance\n * @notice The OndoRateLimiter contract manages rate limits for subscriptions\n *         and redemptions. It allows the configuration of global rate limits for all users and\n *         specific rate limits for individual users. Even if a user has a specific rate limit,\n *         the global rate limit will always be respected. The rate limits are defined in\n *         terms of a maximum allowable amount (in USD with 18 decimals) within a specified window.\n */\ncontract OndoRateLimiter is IOndoRateLimiter, AccessControlEnumerable {\n  /// Role for the client contracts using this rate limiter\n  bytes32 public constant CLIENT_ROLE = keccak256(\"CLIENT_ROLE\");\n\n  /// Role for the admin who can configure the rate limit state for users\n  bytes32 public constant CONFIGURER_ROLE = keccak256(\"CONFIGURER_ROLE\");\n\n  /**\n   * @notice Rate Limit struct\n   * @param  capacityUsed Current amount (in USD with 18 decimals) within the rate limit window\n   * @param  lastUpdated  Timestamp (in seconds) representing the last time the rate limit was\n   *                      checked and updated\n   * @param  limit        This represents the maximum allowed amount (in USD with 18 decimals)\n   *                      within a given window\n   * @param  window       Defines the duration (in seconds) of the rate limiting window\n   */\n  struct RateLimit {\n    uint256 capacityUsed;\n    uint256 lastUpdated;\n    uint256 limit;\n    uint48 window;\n  }\n\n  /**\n   * @notice Rate Limit configuration struct\n   * @param  limit  The maximum allowable amount (in USD with 18 decimals) within the specified window\n   * @param  window The time window (in seconds) for which the limit applies\n   */\n  struct RateLimitConfig {\n    uint256 limit;\n    uint48 window;\n  }\n\n  /// Global rate limits for subscriptions for each RWA token\n  mapping(address /* rwaToken */ => RateLimit) public globalSubscriptionLimits;\n\n  /// Global rate limits for redemptions for each RWA token\n  mapping(address /* rwaToken */ => RateLimit) public globalRedemptionLimits;\n\n  /// User-specific rate limits for subscriptions for each RWA token\n  mapping(address /* rwaToken */ => mapping(bytes32 /* user ID */ => RateLimit))\n    public userSubscriptionLimits;\n\n  /// User-specific rate limits for redemptions for each RWA token\n  mapping(address /* rwaToken */ => mapping(bytes32 /* user ID */ => RateLimit))\n    public userRedemptionLimits;\n\n  /// Default user rate limit configurations for subscriptions for each RWA token\n  mapping(address /* rwaToken */ => RateLimitConfig)\n    public defaultUserSubscriptionLimitConfigs;\n\n  /// Default user rate limit configurations for redemptions for each RWA token\n  mapping(address /* rwaToken */ => RateLimitConfig)\n    public defaultUserRedemptionLimitConfigs;\n\n  /**\n   * @notice Event emitted when `setGlobalSubscriptionLimit` or `setGlobalRedemptionLimit` is\n   *         called\n   * @param  transactionType The type of transaction (SUBSCRIPTION or REDEMPTION)\n   *                         the new limit applies to.\n   * @param  rwaToken        The address of the RWA token the new limit applies to\n   * @param  limit           The new maximum allowable amount (in USD) within the specified window\n   * @param  window          The new time window (in seconds) for which the limit applies\n   */\n  event GlobalRateLimitSet(\n    TransactionType transactionType,\n    address rwaToken,\n    uint256 limit,\n    uint48 window\n  );\n\n  /**\n   * @notice Event emitted when `setDefaultUserSubscriptionLimitConfig` or\n   *         `setDefaultUserRedemptionLimitConfig` is called\n   * @param  transactionType The type of transaction (SUBSCRIPTION or REDEMPTION) the new\n   *                         limit applies to.\n   * @param  rwaToken        The address of the RWA token the new limit applies to\n   * @param  limit           The new maximum allowable amount (in USD) within the specified window\n   * @param  window          The new time window (in seconds) for which the limit applies\n   */\n  event DefaultUserRateLimitSet(\n    TransactionType transactionType,\n    address rwaToken,\n    uint256 limit,\n    uint48 window\n  );\n\n  /**\n   * @notice Event emitted when `setUserSubscriptionRateLimit` or\n   *         `setUserRedemptionRateLimit` is called\n   * @param  transactionType The type of transaction (SUBSCRIPTION or REDEMPTION) the new limit applies to\n   * @param  rwaToken        The address of the RWA token the new limit applies to\n   * @param  userID          The ID of the user the new limit applies to\n   * @param  limit           The new maximum allowable amount (in USD) within the specified window\n   * @param  window          The new time window (in seconds) for which the limit applies\n   */\n  event UserRateLimitSet(\n    TransactionType transactionType,\n    address rwaToken,\n    bytes32 userID,\n    uint256 limit,\n    uint48 window\n  );\n\n  /// Error thrown when an amount exceeds the rate limiter\n  error RateLimitExceeded();\n\n  /// Error thrown when the global rate limit is not set\n  error GlobalRateLimitNotSet();\n\n  /// Error thrown when the default user rate limit is not set\n  error DefaultUserRateLimitNotSet();\n\n  /// Error thrown when attempting to set a rate limit for an RWAToken with zero address\n  error RWAAddressCantBeZero();\n\n  /// Error thrown when attempting to set a rate limit for a user with zero ID\n  error UserIDCantBeZero();\n\n  /**\n   * @param guardian The address of the guardian who will be granted the default admin role\n   */\n  constructor(address guardian) {\n    _grantRole(DEFAULT_ADMIN_ROLE, guardian);\n  }\n\n  /**\n   * @notice Checks and updates the rate limit for a given user and RWA token\n   * @param  transactionType The type of transaction (SUBSCRIPTION or REDEMPTION)\n   * @param  rwaToken        The address of the RWA token being transacted\n   * @param  userID          The ID of the user\n   * @param  usdValue        The value of the transaction, in USD with 18 decimals\n   */\n  function checkAndUpdateRateLimit(\n    TransactionType transactionType,\n    address rwaToken,\n    bytes32 userID,\n    uint256 usdValue\n  ) external onlyRole(CLIENT_ROLE) {\n    RateLimit storage globalRl = transactionType == TransactionType.SUBSCRIPTION\n      ? globalSubscriptionLimits[rwaToken]\n      : globalRedemptionLimits[rwaToken];\n\n    if (globalRl.lastUpdated == 0) revert GlobalRateLimitNotSet();\n\n    // Get global available capacity based on the rate limit configuration and time elapsed\n    (\n      uint256 globalCurrentCapacityUsed,\n      uint256 globalAvailableCapacity\n    ) = _calculateDecay(\n        globalRl.capacityUsed,\n        globalRl.lastUpdated,\n        globalRl.limit,\n        globalRl.window\n      );\n\n    if (usdValue > globalAvailableCapacity) revert RateLimitExceeded();\n\n    RateLimit storage userRl = transactionType == TransactionType.SUBSCRIPTION\n      ? userSubscriptionLimits[rwaToken][userID]\n      : userRedemptionLimits[rwaToken][userID];\n\n    // If the user rate limit has not been set, instantiate it with the default configuration\n    if (userRl.lastUpdated == 0)\n      _instantiateUserRateLimits(transactionType, rwaToken, userID);\n\n    // Get user's available capacity based on the rate limit configuration and time elapsed\n    (\n      uint256 userCurrentCapacityUsed,\n      uint256 userAvailableCapacity\n    ) = _calculateDecay(\n        userRl.capacityUsed,\n        userRl.lastUpdated,\n        userRl.limit,\n        userRl.window\n      );\n\n    if (usdValue > userAvailableCapacity) revert RateLimitExceeded();\n\n    globalRl.capacityUsed = globalCurrentCapacityUsed + usdValue;\n    globalRl.lastUpdated = block.timestamp;\n    userRl.capacityUsed = userCurrentCapacityUsed + usdValue;\n    userRl.lastUpdated = block.timestamp;\n  }\n\n  /**\n   * @notice Instantiates the rate limit state for a new user based on the default configuration\n   * @param  transactionType The type of transaction (SUBSCRIPTION or REDEMPTION) for which\n   *         the rate limit is being set\n   * @param  rwaToken        The address of the RWA token for which the rate limit is being set\n   * @param  userID          The ID of the user for which the rate limit is being set\n   * @dev    In order to transact, a default rate limit configuration must be set for users\n   */\n  function _instantiateUserRateLimits(\n    TransactionType transactionType,\n    address rwaToken,\n    bytes32 userID\n  ) internal {\n    RateLimitConfig memory rlConfig = transactionType ==\n      TransactionType.SUBSCRIPTION\n      ? defaultUserSubscriptionLimitConfigs[rwaToken]\n      : defaultUserRedemptionLimitConfigs[rwaToken];\n    if (rlConfig.limit == 0) revert DefaultUserRateLimitNotSet();\n\n    RateLimit storage userRl = transactionType == TransactionType.SUBSCRIPTION\n      ? userSubscriptionLimits[rwaToken][userID]\n      : userRedemptionLimits[rwaToken][userID];\n\n    userRl.capacityUsed = 0;\n    userRl.lastUpdated = block.timestamp;\n    userRl.limit = rlConfig.limit;\n    userRl.window = rlConfig.window;\n  }\n\n  /**\n   * @notice Calculates the current capacity used and the available capacity based on the rate\n   *         limit configuration and time elapsed\n   * @param  _capacityUsed       The total capacity used at the last update\n   * @param  _lastUpdated        The timestamp (in seconds) when the last update occurred\n   * @param  _limit              The maximum allowable amount within the specified window\n   * @param  _window             The time window (in seconds) for which the limit applies\n   * @return currentCapacityUsed The decayed amount of capacity used based on the elapsed time\n   *                             since `lastUpdated`. If the time since `lastUpdated` exceeds the\n   *                             window, it returns zero.\n   * @return availableCapacity   The amount of capacity available for new activity. If the time\n   *                             since lastUpdated exceeds the window, it returns the full limit.\n   * @dev    This function applies a linear decay model to compute how much of the 'capacityUsed'\n   *         remains based on the time elapsed since the last update.\n   */\n  function _calculateDecay(\n    uint256 _capacityUsed,\n    uint256 _lastUpdated,\n    uint256 _limit,\n    uint48 _window\n  )\n    internal\n    view\n    returns (uint256 currentCapacityUsed, uint256 availableCapacity)\n  {\n    uint256 timeSinceLastUpdate = block.timestamp - _lastUpdated;\n    if (timeSinceLastUpdate >= _window) {\n      return (0, _limit);\n    } else {\n      uint256 decay = (_limit * timeSinceLastUpdate) / _window;\n      currentCapacityUsed = _capacityUsed > decay ? _capacityUsed - decay : 0;\n      availableCapacity = _limit > currentCapacityUsed\n        ? _limit - currentCapacityUsed\n        : 0;\n      return (currentCapacityUsed, availableCapacity);\n    }\n  }\n\n  /**\n   * @notice Returns the current global subscription limit for a given RWA token,\n   *         factoring in the decay\n   * @param  rwaToken            The address of the RWA token\n   * @return currentCapacityUsed The current capacity used based on the decay model\n   * @return availableCapacity   The available capacity for new subscriptions\n   */\n  function getCurrentGlobalSubscriptionLimit(\n    address rwaToken\n  )\n    external\n    view\n    returns (uint256 currentCapacityUsed, uint256 availableCapacity)\n  {\n    RateLimit memory rl = globalSubscriptionLimits[rwaToken];\n    return\n      _calculateDecay(rl.capacityUsed, rl.lastUpdated, rl.limit, rl.window);\n  }\n\n  /**\n   * @notice Returns current global redemption limit for a given RWA token,\n   *         factoring in the decay\n   * @param  rwaToken            The address of the RWA token\n   * @return currentCapacityUsed The current capacity used based on the decay model\n   * @return availableCapacity   The available capacity for new redemptions\n   */\n  function getCurrentGlobalRedemptionLimit(\n    address rwaToken\n  )\n    external\n    view\n    returns (uint256 currentCapacityUsed, uint256 availableCapacity)\n  {\n    RateLimit memory rl = globalRedemptionLimits[rwaToken];\n    return\n      _calculateDecay(rl.capacityUsed, rl.lastUpdated, rl.limit, rl.window);\n  }\n\n  /**\n   * @notice Returns the current subscription limit for a given user,\n   *         factoring in the decay\n   * @param  rwaToken            The address of the RWA token\n   * @param  userID              The ID of the user\n   * @return currentCapacityUsed The current capacity used based on the decay model\n   * @return availableCapacity   The available capacity for new subscriptions\n   */\n  function getCurrentUserSubscriptionLimit(\n    address rwaToken,\n    bytes32 userID\n  )\n    external\n    view\n    returns (uint256 currentCapacityUsed, uint256 availableCapacity)\n  {\n    RateLimit memory rl = userSubscriptionLimits[rwaToken][userID];\n    return\n      _calculateDecay(rl.capacityUsed, rl.lastUpdated, rl.limit, rl.window);\n  }\n\n  /**\n   * @notice Returns the current redemption limit for a given user, factoring in\n   *         the decay.\n   * @param  rwaToken            The address of the RWA token\n   * @param  userID              The ID of the user\n   * @return currentCapacityUsed The current capacity used based on the decay model\n   * @return availableCapacity   The available capacity for new redemptions\n   */\n  function getCurrentUserRedemptionLimit(\n    address rwaToken,\n    bytes32 userID\n  )\n    external\n    view\n    returns (uint256 currentCapacityUsed, uint256 availableCapacity)\n  {\n    RateLimit memory rl = userRedemptionLimits[rwaToken][userID];\n    return\n      _calculateDecay(rl.capacityUsed, rl.lastUpdated, rl.limit, rl.window);\n  }\n\n  /**\n   * @notice Sets the global subscription limit for a given RWA token.\n   * @param  rwaToken The address of the RWA token.\n   * @param  limit    The maximum allowable amount (in USD) within the specified window.\n   * @param  window   The time window (in seconds) for which the limit applies.\n   */\n  function setGlobalSubscriptionLimit(\n    address rwaToken,\n    uint256 limit,\n    uint48 window\n  ) external onlyRole(CONFIGURER_ROLE) {\n    if (rwaToken == address(0)) revert RWAAddressCantBeZero();\n\n    globalSubscriptionLimits[rwaToken] = RateLimit({\n      capacityUsed: 0,\n      lastUpdated: block.timestamp,\n      limit: limit,\n      window: window\n    });\n\n    emit GlobalRateLimitSet(\n      TransactionType.SUBSCRIPTION,\n      rwaToken,\n      limit,\n      window\n    );\n  }\n\n  /**\n   * @notice Sets the global redemption limit for a given RWA token.\n   * @param  rwaToken The address of the RWA token.\n   * @param  limit    The maximum allowable amount (in USD) within the specified window.\n   * @param  window   The time window (in seconds) for which the limit applies.\n   */\n  function setGlobalRedemptionLimit(\n    address rwaToken,\n    uint256 limit,\n    uint48 window\n  ) external onlyRole(CONFIGURER_ROLE) {\n    if (rwaToken == address(0)) revert RWAAddressCantBeZero();\n\n    globalRedemptionLimits[rwaToken] = RateLimit({\n      capacityUsed: 0,\n      lastUpdated: block.timestamp,\n      limit: limit,\n      window: window\n    });\n\n    emit GlobalRateLimitSet(\n      TransactionType.REDEMPTION,\n      rwaToken,\n      limit,\n      window\n    );\n  }\n\n  /**\n   * @notice Sets the default subscription limit configuration for a given RWA token.\n   * @param  rwaToken The address of the RWA token.\n   * @param  limit    The maximum allowable amount (in USD) within the specified window.\n   * @param  window   The time window (in seconds) for which the limit applies.\n   */\n  function setDefaultUserSubscriptionLimitConfig(\n    address rwaToken,\n    uint256 limit,\n    uint48 window\n  ) external onlyRole(CONFIGURER_ROLE) {\n    if (rwaToken == address(0)) revert RWAAddressCantBeZero();\n\n    defaultUserSubscriptionLimitConfigs[rwaToken] = RateLimitConfig({\n      limit: limit,\n      window: window\n    });\n\n    emit DefaultUserRateLimitSet(\n      TransactionType.SUBSCRIPTION,\n      rwaToken,\n      limit,\n      window\n    );\n  }\n\n  /**\n   * @notice Sets the default redemption limit configuration for a given RWA token.\n   * @param  rwaToken The address of the RWA token.\n   * @param  limit    The maximum allowable amount (in USD) within the specified window.\n   * @param  window   The time window (in seconds) for which the limit applies.\n   */\n  function setDefaultUserRedemptionLimitConfig(\n    address rwaToken,\n    uint256 limit,\n    uint48 window\n  ) external onlyRole(CONFIGURER_ROLE) {\n    if (rwaToken == address(0)) revert RWAAddressCantBeZero();\n\n    defaultUserRedemptionLimitConfigs[rwaToken] = RateLimitConfig({\n      limit: limit,\n      window: window\n    });\n\n    emit DefaultUserRateLimitSet(\n      TransactionType.REDEMPTION,\n      rwaToken,\n      limit,\n      window\n    );\n  }\n\n  /**\n   * @notice Sets the subscription rate limit for a specific user.\n   * @param  rwaToken           The address of the RWA token.\n   * @param  userID             The ID of the user.\n   * @param  subscriptionLimit  The maximum allowable amount (in USD) within the specified window.\n   * @param  subscriptionWindow The time window (in seconds) for which the limit applies.\n   */\n  function setUserSubscriptionRateLimit(\n    address rwaToken,\n    bytes32 userID,\n    uint256 subscriptionLimit,\n    uint48 subscriptionWindow\n  ) external onlyRole(CONFIGURER_ROLE) {\n    if (rwaToken == address(0)) revert RWAAddressCantBeZero();\n    if (userID == 0) revert UserIDCantBeZero();\n\n    userSubscriptionLimits[rwaToken][userID] = RateLimit({\n      capacityUsed: 0,\n      lastUpdated: block.timestamp,\n      limit: subscriptionLimit,\n      window: subscriptionWindow\n    });\n\n    emit UserRateLimitSet(\n      TransactionType.SUBSCRIPTION,\n      rwaToken,\n      userID,\n      subscriptionLimit,\n      subscriptionWindow\n    );\n  }\n\n  /**\n   * @notice Sets the redemption rate limit for a specific user.\n   * @param  rwaToken         The address of the RWA token\n   * @param  userID           The ID of the user\n   * @param  redemptionLimit  The maximum allowable amount (in USD) within the specified window\n   * @param  redemptionWindow The time window (in seconds) for which the limit applies\n   */\n  function setUserRedemptionRateLimit(\n    address rwaToken,\n    bytes32 userID,\n    uint256 redemptionLimit,\n    uint48 redemptionWindow\n  ) external onlyRole(CONFIGURER_ROLE) {\n    if (rwaToken == address(0)) revert RWAAddressCantBeZero();\n    if (userID == 0) revert UserIDCantBeZero();\n\n    userRedemptionLimits[rwaToken][userID] = RateLimit({\n      capacityUsed: 0,\n      lastUpdated: block.timestamp,\n      limit: redemptionLimit,\n      window: redemptionWindow\n    });\n\n    emit UserRateLimitSet(\n      TransactionType.REDEMPTION,\n      rwaToken,\n      userID,\n      redemptionLimit,\n      redemptionWindow\n    );\n  }\n}\n","deployed_bytecode":"0x608060405234801561001057600080fd5b50600436106101c35760003560e01c80637f01ed89116100f9578063b6ee2ef511610097578063ca15c87311610071578063ca15c8731461050b578063cd6ea8e41461051e578063d547741f1461054d578063eae6f6521461056057600080fd5b8063b6ee2ef5146104d2578063b6ee3624146104e5578063c1c48984146104f857600080fd5b806391d14854116100d357806391d148541461048f578063a217fddf146104a2578063ab9613dd146104aa578063abbb9f4c146104bd57600080fd5b80637f01ed891461043e5780638a75d46f146104515780639010d07c1461046457600080fd5b80632f2ff15d11610166578063435e3a0811610140578063435e3a081461038e578063452f35a2146103cd57806361d925cb146104185780637d4945b71461042b57600080fd5b80632f2ff15d1461034057806336568abe1461035357806337866b8f1461036657600080fd5b80631989e499116101a25780631989e499146102755780631f50eecb14610288578063248a9ca3146102d0578063259ae9381461030157600080fd5b8062decd57146101c857806301ffc9a71461023d5780630f36a80b14610260575b600080fd5b6102106101d636600461170c565b600460209081526000928352604080842090915290825290208054600182015460028301546003909301549192909165ffffffffffff1684565b6040805194855260208501939093529183015265ffffffffffff1660608201526080015b60405180910390f35b61025061024b366004611736565b610587565b6040519015158152602001610234565b61027361026e366004611776565b6105b2565b005b6102736102833660046117bc565b6106d0565b61021061029636600461170c565b600560209081526000928352604080842090915290825290208054600182015460028301546003909301549192909165ffffffffffff1684565b6102f36102de3660046117f8565b60009081526020819052604090206001015490565b604051908152602001610234565b61021061030f366004611811565b600360208190526000918252604090912080546001820154600283015492909301549092919065ffffffffffff1684565b61027361034e36600461182c565b6107a2565b61027361036136600461182c565b6107cd565b61037961037436600461170c565b610850565b60408051928352602083019190915201610234565b61021061039c366004611811565b600260208190526000918252604090912080546001820154928201546003909201549092919065ffffffffffff1684565b6103fc6103db366004611811565b6006602052600090815260409020805460019091015465ffffffffffff1682565b6040805192835265ffffffffffff909116602083015201610234565b6102736104263660046117bc565b6108c6565b610273610439366004611858565b6109ad565b61037961044c366004611811565b610ba0565b61027361045f3660046117bc565b610c0b565b6104776104723660046118a0565b610cd3565b6040516001600160a01b039091168152602001610234565b61025061049d36600461182c565b610cf2565b6102f3600081565b6102736104b83660046117bc565b610d1b565b6102f3600080516020611b1983398151915281565b6103796104e0366004611811565b610e02565b6102736104f3366004611776565b610e62565b61037961050636600461170c565b610f76565b6102f36105193660046117f8565b610fe0565b6103fc61052c366004611811565b6007602052600090815260409020805460019091015465ffffffffffff1682565b61027361055b36600461182c565b610ff7565b6102f37fa5ff3ec7a96cdbba4d2d5172d66bbc73c6db3885f29b21be5da9fa7a7c02523281565b60006001600160e01b03198216635a05180f60e01b14806105ac57506105ac826110b6565b92915050565b600080516020611b198339815191526105cb81336110eb565b6001600160a01b0385166105f25760405163a04472bf60e01b815260040160405180910390fd5b6000849003610614576040516310bb42ab60e01b815260040160405180910390fd5b60408051608081018252600080825242602080840191825283850188815265ffffffffffff888116606087019081526001600160a01b038d168652600484528786208c87529093528685209551865592516001860155516002850155516003909301805465ffffffffffff1916939091169290921790915590517f080e2829ffdf0bfdba11b72075d05e96e54668c10022757045e019361c42b13f916106c19188908890889088906118fa565b60405180910390a15050505050565b600080516020611b198339815191526106e981336110eb565b6001600160a01b0384166107105760405163a04472bf60e01b815260040160405180910390fd5b60408051808201825284815265ffffffffffff84811660208084019182526001600160a01b0389166000908152600790915284902092518355516001928301805465ffffffffffff19169190921617905590517ffea502c05df8e0d99757f2169af37f199479eae2681b84192295d56bbab3a4e7916107949187908790879061193c565b60405180910390a150505050565b6000828152602081905260409020600101546107be81336110eb565b6107c8838361114f565b505050565b6001600160a01b03811633146108425760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b61084c8282611171565b5050565b6001600160a01b03821660009081526004602090815260408083208484528252808320815160808101835281548082526001830154948201859052600283015493820184905260039092015465ffffffffffff1660608201819052859491936108ba939291611193565b92509250509250929050565b600080516020611b198339815191526108df81336110eb565b6001600160a01b0384166109065760405163a04472bf60e01b815260040160405180910390fd5b60408051608081018252600080825242602080840191825283850188815265ffffffffffff888116606087019081526001600160a01b038c168652600293849052878620965187559351600187015590519185019190915590516003909301805465ffffffffffff1916939091169290921790915590517e37e03ec575b1c5076e32dabd3ea90880aab88cb56b5d9cc9cc27038008e74e916107949187908790879061193c565b7fa5ff3ec7a96cdbba4d2d5172d66bbc73c6db3885f29b21be5da9fa7a7c0252326109d881336110eb565b6000808660018111156109ed576109ed6118c2565b14610a0f576001600160a01b0385166000908152600360205260409020610a28565b6001600160a01b03851660009081526002602052604090205b90508060010154600003610a4e576040516203f19d60ee1b815260040160405180910390fd5b80546001820154600283015460038401546000938493610a7a93919290919065ffffffffffff16611193565b9150915080851115610a9f5760405163a74c1c5f60e01b815260040160405180910390fd5b600080896001811115610ab457610ab46118c2565b14610ae1576001600160a01b03881660009081526005602090815260408083208a84529091529020610b05565b6001600160a01b03881660009081526004602090815260408083208a845290915290205b90508060010154600003610b1e57610b1e898989611220565b80546001820154600283015460038401546000938493610b4a93919290919065ffffffffffff16611193565b9150915080881115610b6f5760405163a74c1c5f60e01b815260040160405180910390fd5b610b79888661198c565b8655426001870155610b8b888361198c565b83555050426001909101555050505050505050565b6001600160a01b03811660009081526002602081815260408084208151608081018352815480825260018301549482018590529482015492810183905260039091015465ffffffffffff166060820181905285949193610c01939091611193565b9250925050915091565b600080516020611b19833981519152610c2481336110eb565b6001600160a01b038416610c4b5760405163a04472bf60e01b815260040160405180910390fd5b60408051808201825284815265ffffffffffff84811660208084019182526001600160a01b038916600090815260069091528481209351845590516001909301805465ffffffffffff19169390921692909217905590517ffea502c05df8e0d99757f2169af37f199479eae2681b84192295d56bbab3a4e7916107949187908790879061193c565b6000828152600160205260408120610ceb9083611358565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b600080516020611b19833981519152610d3481336110eb565b6001600160a01b038416610d5b5760405163a04472bf60e01b815260040160405180910390fd5b60408051608081018252600080825242602080840191825283850188815265ffffffffffff888116606087019081526001600160a01b038c168652600393849052948790209551865592516001808701919091559051600286015592519301805465ffffffffffff1916939091169290921790915590517e37e03ec575b1c5076e32dabd3ea90880aab88cb56b5d9cc9cc27038008e74e916107949187908790879061193c565b6001600160a01b03811660009081526003602081815260408084208151608081018352815480825260018301549482018590526002830154938201849052919094015465ffffffffffff1660608501819052859493610c01939091611193565b600080516020611b19833981519152610e7b81336110eb565b6001600160a01b038516610ea25760405163a04472bf60e01b815260040160405180910390fd5b6000849003610ec4576040516310bb42ab60e01b815260040160405180910390fd5b60408051608081018252600080825242602080840191825283850188815265ffffffffffff888116606087019081526001600160a01b038d168652600584528786208c87529093529386902094518555915160018086019190915591516002850155516003909301805465ffffffffffff19169390921692909217905590517f080e2829ffdf0bfdba11b72075d05e96e54668c10022757045e019361c42b13f916106c19188908890889088906118fa565b6001600160a01b03821660009081526005602090815260408083208484528252808320815160808101835281548082526001830154948201859052600283015493820184905260039092015465ffffffffffff1660608201819052859491936108ba939291611193565b60008181526001602052604081206105ac90611364565b60008281526020819052604090206001015461101381336110eb565b6107c88383611171565b6110278282610cf2565b61084c576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561105d3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610ceb836001600160a01b03841661136e565b60006001600160e01b03198216637965db0b60e01b14806105ac57506301ffc9a760e01b6001600160e01b03198316146105ac565b6110f58282610cf2565b61084c5761110d816001600160a01b031660146113bd565b6111188360206113bd565b6040516020016111299291906119c3565b60408051601f198184030181529082905262461bcd60e51b825261083991600401611a38565b611159828261101d565b60008281526001602052604090206107c890826110a1565b61117b8282611559565b60008281526001602052604090206107c890826115be565b600080806111a18642611a6b565b90508365ffffffffffff1681106111bf576000859250925050611217565b600065ffffffffffff85166111d48388611a7e565b6111de9190611a9d565b90508088116111ee5760006111f8565b6111f88189611a6b565b9350838611611208576000611212565b6112128487611a6b565b925050505b94509492505050565b600080846001811115611235576112356118c2565b14611257576001600160a01b0383166000908152600760205260409020611270565b6001600160a01b03831660009081526006602052604090205b60408051808201909152815480825260019092015465ffffffffffff16602082015291506000036112b45760405163021a286760e21b815260040160405180910390fd5b6000808560018111156112c9576112c96118c2565b146112f6576001600160a01b0384166000908152600560209081526040808320868452909152902061131a565b6001600160a01b038416600090815260046020908152604080832086845290915290205b60008155426001820155825160028201556020909201516003909201805465ffffffffffff191665ffffffffffff9093169290921790915550505050565b6000610ceb83836115d3565b60006105ac825490565b60008181526001830160205260408120546113b5575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105ac565b5060006105ac565b606060006113cc836002611a7e565b6113d790600261198c565b67ffffffffffffffff8111156113ef576113ef611abf565b6040519080825280601f01601f191660200182016040528015611419576020820181803683370190505b509050600360fc1b8160008151811061143457611434611ad5565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061146357611463611ad5565b60200101906001600160f81b031916908160001a9053506000611487846002611a7e565b61149290600161198c565b90505b600181111561150a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106114c6576114c6611ad5565b1a60f81b8282815181106114dc576114dc611ad5565b60200101906001600160f81b031916908160001a90535060049490941c9361150381611aeb565b9050611495565b508315610ceb5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610839565b6115638282610cf2565b1561084c576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610ceb836001600160a01b0384166115fd565b60008260000182815481106115ea576115ea611ad5565b9060005260206000200154905092915050565b600081815260018301602052604081205480156116e6576000611621600183611a6b565b855490915060009061163590600190611a6b565b905081811461169a57600086600001828154811061165557611655611ad5565b906000526020600020015490508087600001848154811061167857611678611ad5565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806116ab576116ab611b02565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105ac565b60009150506105ac565b80356001600160a01b038116811461170757600080fd5b919050565b6000806040838503121561171f57600080fd5b611728836116f0565b946020939093013593505050565b60006020828403121561174857600080fd5b81356001600160e01b031981168114610ceb57600080fd5b803565ffffffffffff8116811461170757600080fd5b6000806000806080858703121561178c57600080fd5b611795856116f0565b935060208501359250604085013591506117b160608601611760565b905092959194509250565b6000806000606084860312156117d157600080fd5b6117da846116f0565b9250602084013591506117ef60408501611760565b90509250925092565b60006020828403121561180a57600080fd5b5035919050565b60006020828403121561182357600080fd5b610ceb826116f0565b6000806040838503121561183f57600080fd5b8235915061184f602084016116f0565b90509250929050565b6000806000806080858703121561186e57600080fd5b84356002811061187d57600080fd5b935061188b602086016116f0565b93969395505050506040820135916060013590565b600080604083850312156118b357600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b600281106118f657634e487b7160e01b600052602160045260246000fd5b9052565b60a0810161190882886118d8565b6001600160a01b039590951660208201526040810193909352606083019190915265ffffffffffff16608090910152919050565b6080810161194a82876118d8565b6001600160a01b03949094166020820152604081019290925265ffffffffffff16606090910152919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156105ac576105ac611976565b60005b838110156119ba5781810151838201526020016119a2565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516119fb81601785016020880161199f565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351611a2c81602884016020880161199f565b01602801949350505050565b6020815260008251806020840152611a5781604085016020870161199f565b601f01601f19169190910160400192915050565b818103818111156105ac576105ac611976565b6000816000190483118215151615611a9857611a98611976565b500290565b600082611aba57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600081611afa57611afa611976565b506000190190565b634e487b7160e01b600052603160045260246000fdfef45c97b23e2beeefda80e1ce5cb3e234aa7b6888ad5cbabb75bfd654dd8e102da26469706673582212202332c685f8127d74484771f07510282169bb14d75c7ab830346209f859e32b6c64736f6c63430008100033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"london","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":200},"remappings":[":@aragon/=node_modules/@aragon/",":@ensdomains/=node_modules/@ensdomains/",":@openzeppelin/=node_modules/@openzeppelin/",":@uniswap/=node_modules/@uniswap/",":eth-gas-reporter/=node_modules/eth-gas-reporter/",":forge-std/=lib/forge-std/src/",":forge-tests/=forge-tests/",":hardhat-deploy/=node_modules/hardhat-deploy/",":hardhat/=node_modules/hardhat/",":lib/=lib/",":math/=node_modules/@aragon/os/contracts/lib/math/",":misc/=node_modules/@aragon/os/contracts/lib/misc/",":solidity-bytes-utils/=node_modules/solidity-bytes-utils/",":standards/=node_modules/@aragon/os/contracts/lib/standards/",":token/=node_modules/@aragon/os/contracts/lib/token/",":truffle/=node_modules/truffle/"]},"optimization_runs":200,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/partial_match/1/0x98Db502215Da1ad9F626D4a0090A8A2f4971003c/","decoded_constructor_args":[["0x094Bee6b74Ec29D32869ae3140A659cAc0482882",{"internalType":"address","name":"guardian","type":"address"}]],"compiler_version":"0.8.16+commit.07a7930e","is_verified_via_verifier_alliance":false,"verified_at":"2025-04-14T05:32:20.825748Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60806040523480156200001157600080fd5b5060405162001d4e38038062001d4e83398101604081905262000034916200019e565b6200004160008262000048565b50620001d0565b6200005f82826200008b60201b6200101d1760201c565b600082815260016020908152604090912062000086918390620010a16200012c821b17901c565b505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000128576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620000e73390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600062000143836001600160a01b0384166200014c565b90505b92915050565b6000818152600183016020526040812054620001955750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000146565b50600062000146565b600060208284031215620001b157600080fd5b81516001600160a01b0381168114620001c957600080fd5b9392505050565b611b6e80620001e06000396000f3fe608060405234801561001057600080fd5b50600436106101c35760003560e01c80637f01ed89116100f9578063b6ee2ef511610097578063ca15c87311610071578063ca15c8731461050b578063cd6ea8e41461051e578063d547741f1461054d578063eae6f6521461056057600080fd5b8063b6ee2ef5146104d2578063b6ee3624146104e5578063c1c48984146104f857600080fd5b806391d14854116100d357806391d148541461048f578063a217fddf146104a2578063ab9613dd146104aa578063abbb9f4c146104bd57600080fd5b80637f01ed891461043e5780638a75d46f146104515780639010d07c1461046457600080fd5b80632f2ff15d11610166578063435e3a0811610140578063435e3a081461038e578063452f35a2146103cd57806361d925cb146104185780637d4945b71461042b57600080fd5b80632f2ff15d1461034057806336568abe1461035357806337866b8f1461036657600080fd5b80631989e499116101a25780631989e499146102755780631f50eecb14610288578063248a9ca3146102d0578063259ae9381461030157600080fd5b8062decd57146101c857806301ffc9a71461023d5780630f36a80b14610260575b600080fd5b6102106101d636600461170c565b600460209081526000928352604080842090915290825290208054600182015460028301546003909301549192909165ffffffffffff1684565b6040805194855260208501939093529183015265ffffffffffff1660608201526080015b60405180910390f35b61025061024b366004611736565b610587565b6040519015158152602001610234565b61027361026e366004611776565b6105b2565b005b6102736102833660046117bc565b6106d0565b61021061029636600461170c565b600560209081526000928352604080842090915290825290208054600182015460028301546003909301549192909165ffffffffffff1684565b6102f36102de3660046117f8565b60009081526020819052604090206001015490565b604051908152602001610234565b61021061030f366004611811565b600360208190526000918252604090912080546001820154600283015492909301549092919065ffffffffffff1684565b61027361034e36600461182c565b6107a2565b61027361036136600461182c565b6107cd565b61037961037436600461170c565b610850565b60408051928352602083019190915201610234565b61021061039c366004611811565b600260208190526000918252604090912080546001820154928201546003909201549092919065ffffffffffff1684565b6103fc6103db366004611811565b6006602052600090815260409020805460019091015465ffffffffffff1682565b6040805192835265ffffffffffff909116602083015201610234565b6102736104263660046117bc565b6108c6565b610273610439366004611858565b6109ad565b61037961044c366004611811565b610ba0565b61027361045f3660046117bc565b610c0b565b6104776104723660046118a0565b610cd3565b6040516001600160a01b039091168152602001610234565b61025061049d36600461182c565b610cf2565b6102f3600081565b6102736104b83660046117bc565b610d1b565b6102f3600080516020611b1983398151915281565b6103796104e0366004611811565b610e02565b6102736104f3366004611776565b610e62565b61037961050636600461170c565b610f76565b6102f36105193660046117f8565b610fe0565b6103fc61052c366004611811565b6007602052600090815260409020805460019091015465ffffffffffff1682565b61027361055b36600461182c565b610ff7565b6102f37fa5ff3ec7a96cdbba4d2d5172d66bbc73c6db3885f29b21be5da9fa7a7c02523281565b60006001600160e01b03198216635a05180f60e01b14806105ac57506105ac826110b6565b92915050565b600080516020611b198339815191526105cb81336110eb565b6001600160a01b0385166105f25760405163a04472bf60e01b815260040160405180910390fd5b6000849003610614576040516310bb42ab60e01b815260040160405180910390fd5b60408051608081018252600080825242602080840191825283850188815265ffffffffffff888116606087019081526001600160a01b038d168652600484528786208c87529093528685209551865592516001860155516002850155516003909301805465ffffffffffff1916939091169290921790915590517f080e2829ffdf0bfdba11b72075d05e96e54668c10022757045e019361c42b13f916106c19188908890889088906118fa565b60405180910390a15050505050565b600080516020611b198339815191526106e981336110eb565b6001600160a01b0384166107105760405163a04472bf60e01b815260040160405180910390fd5b60408051808201825284815265ffffffffffff84811660208084019182526001600160a01b0389166000908152600790915284902092518355516001928301805465ffffffffffff19169190921617905590517ffea502c05df8e0d99757f2169af37f199479eae2681b84192295d56bbab3a4e7916107949187908790879061193c565b60405180910390a150505050565b6000828152602081905260409020600101546107be81336110eb565b6107c8838361114f565b505050565b6001600160a01b03811633146108425760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b61084c8282611171565b5050565b6001600160a01b03821660009081526004602090815260408083208484528252808320815160808101835281548082526001830154948201859052600283015493820184905260039092015465ffffffffffff1660608201819052859491936108ba939291611193565b92509250509250929050565b600080516020611b198339815191526108df81336110eb565b6001600160a01b0384166109065760405163a04472bf60e01b815260040160405180910390fd5b60408051608081018252600080825242602080840191825283850188815265ffffffffffff888116606087019081526001600160a01b038c168652600293849052878620965187559351600187015590519185019190915590516003909301805465ffffffffffff1916939091169290921790915590517e37e03ec575b1c5076e32dabd3ea90880aab88cb56b5d9cc9cc27038008e74e916107949187908790879061193c565b7fa5ff3ec7a96cdbba4d2d5172d66bbc73c6db3885f29b21be5da9fa7a7c0252326109d881336110eb565b6000808660018111156109ed576109ed6118c2565b14610a0f576001600160a01b0385166000908152600360205260409020610a28565b6001600160a01b03851660009081526002602052604090205b90508060010154600003610a4e576040516203f19d60ee1b815260040160405180910390fd5b80546001820154600283015460038401546000938493610a7a93919290919065ffffffffffff16611193565b9150915080851115610a9f5760405163a74c1c5f60e01b815260040160405180910390fd5b600080896001811115610ab457610ab46118c2565b14610ae1576001600160a01b03881660009081526005602090815260408083208a84529091529020610b05565b6001600160a01b03881660009081526004602090815260408083208a845290915290205b90508060010154600003610b1e57610b1e898989611220565b80546001820154600283015460038401546000938493610b4a93919290919065ffffffffffff16611193565b9150915080881115610b6f5760405163a74c1c5f60e01b815260040160405180910390fd5b610b79888661198c565b8655426001870155610b8b888361198c565b83555050426001909101555050505050505050565b6001600160a01b03811660009081526002602081815260408084208151608081018352815480825260018301549482018590529482015492810183905260039091015465ffffffffffff166060820181905285949193610c01939091611193565b9250925050915091565b600080516020611b19833981519152610c2481336110eb565b6001600160a01b038416610c4b5760405163a04472bf60e01b815260040160405180910390fd5b60408051808201825284815265ffffffffffff84811660208084019182526001600160a01b038916600090815260069091528481209351845590516001909301805465ffffffffffff19169390921692909217905590517ffea502c05df8e0d99757f2169af37f199479eae2681b84192295d56bbab3a4e7916107949187908790879061193c565b6000828152600160205260408120610ceb9083611358565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b600080516020611b19833981519152610d3481336110eb565b6001600160a01b038416610d5b5760405163a04472bf60e01b815260040160405180910390fd5b60408051608081018252600080825242602080840191825283850188815265ffffffffffff888116606087019081526001600160a01b038c168652600393849052948790209551865592516001808701919091559051600286015592519301805465ffffffffffff1916939091169290921790915590517e37e03ec575b1c5076e32dabd3ea90880aab88cb56b5d9cc9cc27038008e74e916107949187908790879061193c565b6001600160a01b03811660009081526003602081815260408084208151608081018352815480825260018301549482018590526002830154938201849052919094015465ffffffffffff1660608501819052859493610c01939091611193565b600080516020611b19833981519152610e7b81336110eb565b6001600160a01b038516610ea25760405163a04472bf60e01b815260040160405180910390fd5b6000849003610ec4576040516310bb42ab60e01b815260040160405180910390fd5b60408051608081018252600080825242602080840191825283850188815265ffffffffffff888116606087019081526001600160a01b038d168652600584528786208c87529093529386902094518555915160018086019190915591516002850155516003909301805465ffffffffffff19169390921692909217905590517f080e2829ffdf0bfdba11b72075d05e96e54668c10022757045e019361c42b13f916106c19188908890889088906118fa565b6001600160a01b03821660009081526005602090815260408083208484528252808320815160808101835281548082526001830154948201859052600283015493820184905260039092015465ffffffffffff1660608201819052859491936108ba939291611193565b60008181526001602052604081206105ac90611364565b60008281526020819052604090206001015461101381336110eb565b6107c88383611171565b6110278282610cf2565b61084c576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561105d3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000610ceb836001600160a01b03841661136e565b60006001600160e01b03198216637965db0b60e01b14806105ac57506301ffc9a760e01b6001600160e01b03198316146105ac565b6110f58282610cf2565b61084c5761110d816001600160a01b031660146113bd565b6111188360206113bd565b6040516020016111299291906119c3565b60408051601f198184030181529082905262461bcd60e51b825261083991600401611a38565b611159828261101d565b60008281526001602052604090206107c890826110a1565b61117b8282611559565b60008281526001602052604090206107c890826115be565b600080806111a18642611a6b565b90508365ffffffffffff1681106111bf576000859250925050611217565b600065ffffffffffff85166111d48388611a7e565b6111de9190611a9d565b90508088116111ee5760006111f8565b6111f88189611a6b565b9350838611611208576000611212565b6112128487611a6b565b925050505b94509492505050565b600080846001811115611235576112356118c2565b14611257576001600160a01b0383166000908152600760205260409020611270565b6001600160a01b03831660009081526006602052604090205b60408051808201909152815480825260019092015465ffffffffffff16602082015291506000036112b45760405163021a286760e21b815260040160405180910390fd5b6000808560018111156112c9576112c96118c2565b146112f6576001600160a01b0384166000908152600560209081526040808320868452909152902061131a565b6001600160a01b038416600090815260046020908152604080832086845290915290205b60008155426001820155825160028201556020909201516003909201805465ffffffffffff191665ffffffffffff9093169290921790915550505050565b6000610ceb83836115d3565b60006105ac825490565b60008181526001830160205260408120546113b5575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105ac565b5060006105ac565b606060006113cc836002611a7e565b6113d790600261198c565b67ffffffffffffffff8111156113ef576113ef611abf565b6040519080825280601f01601f191660200182016040528015611419576020820181803683370190505b509050600360fc1b8160008151811061143457611434611ad5565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061146357611463611ad5565b60200101906001600160f81b031916908160001a9053506000611487846002611a7e565b61149290600161198c565b90505b600181111561150a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106114c6576114c6611ad5565b1a60f81b8282815181106114dc576114dc611ad5565b60200101906001600160f81b031916908160001a90535060049490941c9361150381611aeb565b9050611495565b508315610ceb5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610839565b6115638282610cf2565b1561084c576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000610ceb836001600160a01b0384166115fd565b60008260000182815481106115ea576115ea611ad5565b9060005260206000200154905092915050565b600081815260018301602052604081205480156116e6576000611621600183611a6b565b855490915060009061163590600190611a6b565b905081811461169a57600086600001828154811061165557611655611ad5565b906000526020600020015490508087600001848154811061167857611678611ad5565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806116ab576116ab611b02565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105ac565b60009150506105ac565b80356001600160a01b038116811461170757600080fd5b919050565b6000806040838503121561171f57600080fd5b611728836116f0565b946020939093013593505050565b60006020828403121561174857600080fd5b81356001600160e01b031981168114610ceb57600080fd5b803565ffffffffffff8116811461170757600080fd5b6000806000806080858703121561178c57600080fd5b611795856116f0565b935060208501359250604085013591506117b160608601611760565b905092959194509250565b6000806000606084860312156117d157600080fd5b6117da846116f0565b9250602084013591506117ef60408501611760565b90509250925092565b60006020828403121561180a57600080fd5b5035919050565b60006020828403121561182357600080fd5b610ceb826116f0565b6000806040838503121561183f57600080fd5b8235915061184f602084016116f0565b90509250929050565b6000806000806080858703121561186e57600080fd5b84356002811061187d57600080fd5b935061188b602086016116f0565b93969395505050506040820135916060013590565b600080604083850312156118b357600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b600281106118f657634e487b7160e01b600052602160045260246000fd5b9052565b60a0810161190882886118d8565b6001600160a01b039590951660208201526040810193909352606083019190915265ffffffffffff16608090910152919050565b6080810161194a82876118d8565b6001600160a01b03949094166020820152604081019290925265ffffffffffff16606090910152919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156105ac576105ac611976565b60005b838110156119ba5781810151838201526020016119a2565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516119fb81601785016020880161199f565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351611a2c81602884016020880161199f565b01602801949350505050565b6020815260008251806020840152611a5781604085016020870161199f565b601f01601f19169190910160400192915050565b818103818111156105ac576105ac611976565b6000816000190483118215151615611a9857611a98611976565b500290565b600082611aba57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600081611afa57611afa611976565b506000190190565b634e487b7160e01b600052603160045260246000fdfef45c97b23e2beeefda80e1ce5cb3e234aa7b6888ad5cbabb75bfd654dd8e102da26469706673582212202332c685f8127d74484771f07510282169bb14d75c7ab830346209f859e32b6c64736f6c63430008100033000000000000000000000000094bee6b74ec29d32869ae3140a659cac0482882","name":"OndoRateLimiter","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"london","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"contracts/external/openzeppelin/contracts/access/AccessControl.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"contracts/external/openzeppelin/contracts/access/IAccessControl.sol\";\nimport \"contracts/external/openzeppelin/contracts/utils/Context.sol\";\nimport \"contracts/external/openzeppelin/contracts/utils/Strings.sol\";\nimport \"contracts/external/openzeppelin/contracts/utils/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n  struct RoleData {\n    mapping(address => bool) members;\n    bytes32 adminRole;\n  }\n\n  mapping(bytes32 => RoleData) private _roles;\n\n  bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n  /**\n   * @dev Modifier that checks that an account has a specific role. Reverts\n   * with a standardized message including the required role.\n   *\n   * The format of the revert reason is given by the following regular expression:\n   *\n   *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n   *\n   * _Available since v4.1._\n   */\n  modifier onlyRole(bytes32 role) {\n    _checkRole(role, _msgSender());\n    _;\n  }\n\n  /**\n   * @dev See {IERC165-supportsInterface}.\n   */\n  function supportsInterface(bytes4 interfaceId)\n    public\n    view\n    virtual\n    override\n    returns (bool)\n  {\n    return\n      interfaceId == type(IAccessControl).interfaceId ||\n      super.supportsInterface(interfaceId);\n  }\n\n  /**\n   * @dev Returns `true` if `account` has been granted `role`.\n   */\n  function hasRole(bytes32 role, address account)\n    public\n    view\n    virtual\n    override\n    returns (bool)\n  {\n    return _roles[role].members[account];\n  }\n\n  /**\n   * @dev Revert with a standard message if `account` is missing `role`.\n   *\n   * The format of the revert reason is given by the following regular expression:\n   *\n   *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n   */\n  function _checkRole(bytes32 role, address account) internal view virtual {\n    if (!hasRole(role, account)) {\n      revert(\n        string(\n          abi.encodePacked(\n            \"AccessControl: account \",\n            Strings.toHexString(uint160(account), 20),\n            \" is missing role \",\n            Strings.toHexString(uint256(role), 32)\n          )\n        )\n      );\n    }\n  }\n\n  /**\n   * @dev Returns the admin role that controls `role`. See {grantRole} and\n   * {revokeRole}.\n   *\n   * To change a role's admin, use {_setRoleAdmin}.\n   */\n  function getRoleAdmin(bytes32 role)\n    public\n    view\n    virtual\n    override\n    returns (bytes32)\n  {\n    return _roles[role].adminRole;\n  }\n\n  /**\n   * @dev Grants `role` to `account`.\n   *\n   * If `account` had not been already granted `role`, emits a {RoleGranted}\n   * event.\n   *\n   * Requirements:\n   *\n   * - the caller must have ``role``'s admin role.\n   */\n  function grantRole(bytes32 role, address account)\n    public\n    virtual\n    override\n    onlyRole(getRoleAdmin(role))\n  {\n    _grantRole(role, account);\n  }\n\n  /**\n   * @dev Revokes `role` from `account`.\n   *\n   * If `account` had been granted `role`, emits a {RoleRevoked} event.\n   *\n   * Requirements:\n   *\n   * - the caller must have ``role``'s admin role.\n   */\n  function revokeRole(bytes32 role, address account)\n    public\n    virtual\n    override\n    onlyRole(getRoleAdmin(role))\n  {\n    _revokeRole(role, account);\n  }\n\n  /**\n   * @dev Revokes `role` from the calling account.\n   *\n   * Roles are often managed via {grantRole} and {revokeRole}: this function's\n   * purpose is to provide a mechanism for accounts to lose their privileges\n   * if they are compromised (such as when a trusted device is misplaced).\n   *\n   * If the calling account had been revoked `role`, emits a {RoleRevoked}\n   * event.\n   *\n   * Requirements:\n   *\n   * - the caller must be `account`.\n   */\n  function renounceRole(bytes32 role, address account) public virtual override {\n    require(\n      account == _msgSender(),\n      \"AccessControl: can only renounce roles for self\"\n    );\n\n    _revokeRole(role, account);\n  }\n\n  /**\n   * @dev Grants `role` to `account`.\n   *\n   * If `account` had not been already granted `role`, emits a {RoleGranted}\n   * event. Note that unlike {grantRole}, this function doesn't perform any\n   * checks on the calling account.\n   *\n   * [WARNING]\n   * ====\n   * This function should only be called from the constructor when setting\n   * up the initial roles for the system.\n   *\n   * Using this function in any other way is effectively circumventing the admin\n   * system imposed by {AccessControl}.\n   * ====\n   *\n   * NOTE: This function is deprecated in favor of {_grantRole}.\n   */\n  function _setupRole(bytes32 role, address account) internal virtual {\n    _grantRole(role, account);\n  }\n\n  /**\n   * @dev Sets `adminRole` as ``role``'s admin role.\n   *\n   * Emits a {RoleAdminChanged} event.\n   */\n  function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n    bytes32 previousAdminRole = getRoleAdmin(role);\n    _roles[role].adminRole = adminRole;\n    emit RoleAdminChanged(role, previousAdminRole, adminRole);\n  }\n\n  /**\n   * @dev Grants `role` to `account`.\n   *\n   * Internal function without access restriction.\n   */\n  function _grantRole(bytes32 role, address account) internal virtual {\n    if (!hasRole(role, account)) {\n      _roles[role].members[account] = true;\n      emit RoleGranted(role, account, _msgSender());\n    }\n  }\n\n  /**\n   * @dev Revokes `role` from `account`.\n   *\n   * Internal function without access restriction.\n   */\n  function _revokeRole(bytes32 role, address account) internal virtual {\n    if (hasRole(role, account)) {\n      _roles[role].members[account] = false;\n      emit RoleRevoked(role, account, _msgSender());\n    }\n  }\n}\n"},{"file_path":"contracts/external/openzeppelin/contracts/access/AccessControlEnumerable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"contracts/external/openzeppelin/contracts/access/IAccessControlEnumerable.sol\";\nimport \"contracts/external/openzeppelin/contracts/access/AccessControl.sol\";\nimport \"contracts/external/openzeppelin/contracts/utils/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is\n  IAccessControlEnumerable,\n  AccessControl\n{\n  using EnumerableSet for EnumerableSet.AddressSet;\n\n  mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n  /**\n   * @dev See {IERC165-supportsInterface}.\n   */\n  function supportsInterface(bytes4 interfaceId)\n    public\n    view\n    virtual\n    override\n    returns (bool)\n  {\n    return\n      interfaceId == type(IAccessControlEnumerable).interfaceId ||\n      super.supportsInterface(interfaceId);\n  }\n\n  /**\n   * @dev Returns one of the accounts that have `role`. `index` must be a\n   * value between 0 and {getRoleMemberCount}, non-inclusive.\n   *\n   * Role bearers are not sorted in any particular way, and their ordering may\n   * change at any point.\n   *\n   * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n   * you perform all queries on the same block. See the following\n   * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n   * for more information.\n   */\n  function getRoleMember(bytes32 role, uint256 index)\n    public\n    view\n    virtual\n    override\n    returns (address)\n  {\n    return _roleMembers[role].at(index);\n  }\n\n  /**\n   * @dev Returns the number of accounts that have `role`. Can be used\n   * together with {getRoleMember} to enumerate all bearers of a role.\n   */\n  function getRoleMemberCount(bytes32 role)\n    public\n    view\n    virtual\n    override\n    returns (uint256)\n  {\n    return _roleMembers[role].length();\n  }\n\n  /**\n   * @dev Overload {_grantRole} to track enumerable memberships\n   */\n  function _grantRole(bytes32 role, address account) internal virtual override {\n    super._grantRole(role, account);\n    _roleMembers[role].add(account);\n  }\n\n  /**\n   * @dev Overload {_revokeRole} to track enumerable memberships\n   */\n  function _revokeRole(bytes32 role, address account)\n    internal\n    virtual\n    override\n  {\n    super._revokeRole(role, account);\n    _roleMembers[role].remove(account);\n  }\n}\n"},{"file_path":"contracts/external/openzeppelin/contracts/access/IAccessControl.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n  /**\n   * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n   *\n   * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n   * {RoleAdminChanged} not being emitted signaling this.\n   *\n   * _Available since v3.1._\n   */\n  event RoleAdminChanged(\n    bytes32 indexed role,\n    bytes32 indexed previousAdminRole,\n    bytes32 indexed newAdminRole\n  );\n\n  /**\n   * @dev Emitted when `account` is granted `role`.\n   *\n   * `sender` is the account that originated the contract call, an admin role\n   * bearer except when using {AccessControl-_setupRole}.\n   */\n  event RoleGranted(\n    bytes32 indexed role,\n    address indexed account,\n    address indexed sender\n  );\n\n  /**\n   * @dev Emitted when `account` is revoked `role`.\n   *\n   * `sender` is the account that originated the contract call:\n   *   - if using `revokeRole`, it is the admin role bearer\n   *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n   */\n  event RoleRevoked(\n    bytes32 indexed role,\n    address indexed account,\n    address indexed sender\n  );\n\n  /**\n   * @dev Returns `true` if `account` has been granted `role`.\n   */\n  function hasRole(bytes32 role, address account) external view returns (bool);\n\n  /**\n   * @dev Returns the admin role that controls `role`. See {grantRole} and\n   * {revokeRole}.\n   *\n   * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n   */\n  function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n  /**\n   * @dev Grants `role` to `account`.\n   *\n   * If `account` had not been already granted `role`, emits a {RoleGranted}\n   * event.\n   *\n   * Requirements:\n   *\n   * - the caller must have ``role``'s admin role.\n   */\n  function grantRole(bytes32 role, address account) external;\n\n  /**\n   * @dev Revokes `role` from `account`.\n   *\n   * If `account` had been granted `role`, emits a {RoleRevoked} event.\n   *\n   * Requirements:\n   *\n   * - the caller must have ``role``'s admin role.\n   */\n  function revokeRole(bytes32 role, address account) external;\n\n  /**\n   * @dev Revokes `role` from the calling account.\n   *\n   * Roles are often managed via {grantRole} and {revokeRole}: this function's\n   * purpose is to provide a mechanism for accounts to lose their privileges\n   * if they are compromised (such as when a trusted device is misplaced).\n   *\n   * If the calling account had been granted `role`, emits a {RoleRevoked}\n   * event.\n   *\n   * Requirements:\n   *\n   * - the caller must be `account`.\n   */\n  function renounceRole(bytes32 role, address account) external;\n}\n"},{"file_path":"contracts/external/openzeppelin/contracts/access/IAccessControlEnumerable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"contracts/external/openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n  /**\n   * @dev Returns one of the accounts that have `role`. `index` must be a\n   * value between 0 and {getRoleMemberCount}, non-inclusive.\n   *\n   * Role bearers are not sorted in any particular way, and their ordering may\n   * change at any point.\n   *\n   * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n   * you perform all queries on the same block. See the following\n   * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n   * for more information.\n   */\n  function getRoleMember(bytes32 role, uint256 index)\n    external\n    view\n    returns (address);\n\n  /**\n   * @dev Returns the number of accounts that have `role`. Can be used\n   * together with {getRoleMember} to enumerate all bearers of a role.\n   */\n  function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n"},{"file_path":"contracts/external/openzeppelin/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n  function _msgSender() internal view virtual returns (address) {\n    return msg.sender;\n  }\n\n  function _msgData() internal view virtual returns (bytes calldata) {\n    return msg.data;\n  }\n}\n"},{"file_path":"contracts/external/openzeppelin/contracts/utils/ERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"contracts/external/openzeppelin/contracts/utils/IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n  /**\n   * @dev See {IERC165-supportsInterface}.\n   */\n  function supportsInterface(bytes4 interfaceId)\n    public\n    view\n    virtual\n    override\n    returns (bool)\n  {\n    return interfaceId == type(IERC165).interfaceId;\n  }\n}\n"},{"file_path":"contracts/external/openzeppelin/contracts/utils/EnumerableSet.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n  // To implement this library for multiple types with as little code\n  // repetition as possible, we write it in terms of a generic Set type with\n  // bytes32 values.\n  // The Set implementation uses private functions, and user-facing\n  // implementations (such as AddressSet) are just wrappers around the\n  // underlying Set.\n  // This means that we can only create new EnumerableSets for types that fit\n  // in bytes32.\n\n  struct Set {\n    // Storage of set values\n    bytes32[] _values;\n    // Position of the value in the `values` array, plus 1 because index 0\n    // means a value is not in the set.\n    mapping(bytes32 => uint256) _indexes;\n  }\n\n  /**\n   * @dev Add a value to a set. O(1).\n   *\n   * Returns true if the value was added to the set, that is if it was not\n   * already present.\n   */\n  function _add(Set storage set, bytes32 value) private returns (bool) {\n    if (!_contains(set, value)) {\n      set._values.push(value);\n      // The value is stored at length-1, but we add 1 to all indexes\n      // and use 0 as a sentinel value\n      set._indexes[value] = set._values.length;\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  /**\n   * @dev Removes a value from a set. O(1).\n   *\n   * Returns true if the value was removed from the set, that is if it was\n   * present.\n   */\n  function _remove(Set storage set, bytes32 value) private returns (bool) {\n    // We read and store the value's index to prevent multiple reads from the same storage slot\n    uint256 valueIndex = set._indexes[value];\n\n    if (valueIndex != 0) {\n      // Equivalent to contains(set, value)\n      // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n      // the array, and then remove the last element (sometimes called as 'swap and pop').\n      // This modifies the order of the array, as noted in {at}.\n\n      uint256 toDeleteIndex = valueIndex - 1;\n      uint256 lastIndex = set._values.length - 1;\n\n      if (lastIndex != toDeleteIndex) {\n        bytes32 lastvalue = set._values[lastIndex];\n\n        // Move the last value to the index where the value to delete is\n        set._values[toDeleteIndex] = lastvalue;\n        // Update the index for the moved value\n        set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex\n      }\n\n      // Delete the slot where the moved value was stored\n      set._values.pop();\n\n      // Delete the index for the deleted slot\n      delete set._indexes[value];\n\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  /**\n   * @dev Returns true if the value is in the set. O(1).\n   */\n  function _contains(Set storage set, bytes32 value)\n    private\n    view\n    returns (bool)\n  {\n    return set._indexes[value] != 0;\n  }\n\n  /**\n   * @dev Returns the number of values on the set. O(1).\n   */\n  function _length(Set storage set) private view returns (uint256) {\n    return set._values.length;\n  }\n\n  /**\n   * @dev Returns the value stored at position `index` in the set. O(1).\n   *\n   * Note that there are no guarantees on the ordering of values inside the\n   * array, and it may change when more values are added or removed.\n   *\n   * Requirements:\n   *\n   * - `index` must be strictly less than {length}.\n   */\n  function _at(Set storage set, uint256 index) private view returns (bytes32) {\n    return set._values[index];\n  }\n\n  /**\n   * @dev Return the entire set in an array\n   *\n   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n   * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n   */\n  function _values(Set storage set) private view returns (bytes32[] memory) {\n    return set._values;\n  }\n\n  // Bytes32Set\n\n  struct Bytes32Set {\n    Set _inner;\n  }\n\n  /**\n   * @dev Add a value to a set. O(1).\n   *\n   * Returns true if the value was added to the set, that is if it was not\n   * already present.\n   */\n  function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n    return _add(set._inner, value);\n  }\n\n  /**\n   * @dev Removes a value from a set. O(1).\n   *\n   * Returns true if the value was removed from the set, that is if it was\n   * present.\n   */\n  function remove(Bytes32Set storage set, bytes32 value)\n    internal\n    returns (bool)\n  {\n    return _remove(set._inner, value);\n  }\n\n  /**\n   * @dev Returns true if the value is in the set. O(1).\n   */\n  function contains(Bytes32Set storage set, bytes32 value)\n    internal\n    view\n    returns (bool)\n  {\n    return _contains(set._inner, value);\n  }\n\n  /**\n   * @dev Returns the number of values in the set. O(1).\n   */\n  function length(Bytes32Set storage set) internal view returns (uint256) {\n    return _length(set._inner);\n  }\n\n  /**\n   * @dev Returns the value stored at position `index` in the set. O(1).\n   *\n   * Note that there are no guarantees on the ordering of values inside the\n   * array, and it may change when more values are added or removed.\n   *\n   * Requirements:\n   *\n   * - `index` must be strictly less than {length}.\n   */\n  function at(Bytes32Set storage set, uint256 index)\n    internal\n    view\n    returns (bytes32)\n  {\n    return _at(set._inner, index);\n  }\n\n  /**\n   * @dev Return the entire set in an array\n   *\n   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n   * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n   */\n  function values(Bytes32Set storage set)\n    internal\n    view\n    returns (bytes32[] memory)\n  {\n    return _values(set._inner);\n  }\n\n  // AddressSet\n\n  struct AddressSet {\n    Set _inner;\n  }\n\n  /**\n   * @dev Add a value to a set. O(1).\n   *\n   * Returns true if the value was added to the set, that is if it was not\n   * already present.\n   */\n  function add(AddressSet storage set, address value) internal returns (bool) {\n    return _add(set._inner, bytes32(uint256(uint160(value))));\n  }\n\n  /**\n   * @dev Removes a value from a set. O(1).\n   *\n   * Returns true if the value was removed from the set, that is if it was\n   * present.\n   */\n  function remove(AddressSet storage set, address value)\n    internal\n    returns (bool)\n  {\n    return _remove(set._inner, bytes32(uint256(uint160(value))));\n  }\n\n  /**\n   * @dev Returns true if the value is in the set. O(1).\n   */\n  function contains(AddressSet storage set, address value)\n    internal\n    view\n    returns (bool)\n  {\n    return _contains(set._inner, bytes32(uint256(uint160(value))));\n  }\n\n  /**\n   * @dev Returns the number of values in the set. O(1).\n   */\n  function length(AddressSet storage set) internal view returns (uint256) {\n    return _length(set._inner);\n  }\n\n  /**\n   * @dev Returns the value stored at position `index` in the set. O(1).\n   *\n   * Note that there are no guarantees on the ordering of values inside the\n   * array, and it may change when more values are added or removed.\n   *\n   * Requirements:\n   *\n   * - `index` must be strictly less than {length}.\n   */\n  function at(AddressSet storage set, uint256 index)\n    internal\n    view\n    returns (address)\n  {\n    return address(uint160(uint256(_at(set._inner, index))));\n  }\n\n  /**\n   * @dev Return the entire set in an array\n   *\n   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n   * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n   */\n  function values(AddressSet storage set)\n    internal\n    view\n    returns (address[] memory)\n  {\n    bytes32[] memory store = _values(set._inner);\n    address[] memory result;\n\n    assembly {\n      result := store\n    }\n\n    return result;\n  }\n\n  // UintSet\n\n  struct UintSet {\n    Set _inner;\n  }\n\n  /**\n   * @dev Add a value to a set. O(1).\n   *\n   * Returns true if the value was added to the set, that is if it was not\n   * already present.\n   */\n  function add(UintSet storage set, uint256 value) internal returns (bool) {\n    return _add(set._inner, bytes32(value));\n  }\n\n  /**\n   * @dev Removes a value from a set. O(1).\n   *\n   * Returns true if the value was removed from the set, that is if it was\n   * present.\n   */\n  function remove(UintSet storage set, uint256 value) internal returns (bool) {\n    return _remove(set._inner, bytes32(value));\n  }\n\n  /**\n   * @dev Returns true if the value is in the set. O(1).\n   */\n  function contains(UintSet storage set, uint256 value)\n    internal\n    view\n    returns (bool)\n  {\n    return _contains(set._inner, bytes32(value));\n  }\n\n  /**\n   * @dev Returns the number of values on the set. O(1).\n   */\n  function length(UintSet storage set) internal view returns (uint256) {\n    return _length(set._inner);\n  }\n\n  /**\n   * @dev Returns the value stored at position `index` in the set. O(1).\n   *\n   * Note that there are no guarantees on the ordering of values inside the\n   * array, and it may change when more values are added or removed.\n   *\n   * Requirements:\n   *\n   * - `index` must be strictly less than {length}.\n   */\n  function at(UintSet storage set, uint256 index)\n    internal\n    view\n    returns (uint256)\n  {\n    return uint256(_at(set._inner, index));\n  }\n\n  /**\n   * @dev Return the entire set in an array\n   *\n   * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n   * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n   * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n   * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n   */\n  function values(UintSet storage set)\n    internal\n    view\n    returns (uint256[] memory)\n  {\n    bytes32[] memory store = _values(set._inner);\n    uint256[] memory result;\n\n    assembly {\n      result := store\n    }\n\n    return result;\n  }\n}\n"},{"file_path":"contracts/external/openzeppelin/contracts/utils/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n  /**\n   * @dev Returns true if this contract implements the interface defined by\n   * `interfaceId`. See the corresponding\n   * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n   * to learn more about how these ids are created.\n   *\n   * This function call must use less than 30 000 gas.\n   */\n  function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"contracts/external/openzeppelin/contracts/utils/Strings.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n  bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n  /**\n   * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n   */\n  function toString(uint256 value) internal pure returns (string memory) {\n    // Inspired by OraclizeAPI's implementation - MIT licence\n    // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n    if (value == 0) {\n      return \"0\";\n    }\n    uint256 temp = value;\n    uint256 digits;\n    while (temp != 0) {\n      digits++;\n      temp /= 10;\n    }\n    bytes memory buffer = new bytes(digits);\n    while (value != 0) {\n      digits -= 1;\n      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n      value /= 10;\n    }\n    return string(buffer);\n  }\n\n  /**\n   * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n   */\n  function toHexString(uint256 value) internal pure returns (string memory) {\n    if (value == 0) {\n      return \"0x00\";\n    }\n    uint256 temp = value;\n    uint256 length = 0;\n    while (temp != 0) {\n      length++;\n      temp >>= 8;\n    }\n    return toHexString(value, length);\n  }\n\n  /**\n   * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n   */\n  function toHexString(uint256 value, uint256 length)\n    internal\n    pure\n    returns (string memory)\n  {\n    bytes memory buffer = new bytes(2 * length + 2);\n    buffer[0] = \"0\";\n    buffer[1] = \"x\";\n    for (uint256 i = 2 * length + 1; i > 1; --i) {\n      buffer[i] = _HEX_SYMBOLS[value & 0xf];\n      value >>= 4;\n    }\n    require(value == 0, \"Strings: hex length insufficient\");\n    return string(buffer);\n  }\n}\n"},{"file_path":"contracts/xManager/interfaces/IOndoRateLimiter.sol","source_code":"// SPDX-License-Identifier: MIT\n/*\n      ▄▄█████████▄\n   ╓██▀└ ,╓▄▄▄, '▀██▄\n  ██▀ ▄██▀▀╙╙▀▀██▄ └██µ           ,,       ,,      ,     ,,,            ,,,\n ██ ,██¬ ▄████▄  ▀█▄ ╙█▄      ▄███▀▀███▄   ███▄    ██  ███▀▀▀███▄    ▄███▀▀███,\n██  ██ ╒█▀'   ╙█▌ ╙█▌ ██     ▐██      ███  █████,  ██  ██▌    └██▌  ██▌     └██▌\n██ ▐█▌ ██      ╟█  █▌ ╟█     ██▌      ▐██  ██ └███ ██  ██▌     ╟██ j██       ╟██\n╟█  ██ ╙██    ▄█▀ ▐█▌ ██     ╙██      ██▌  ██   ╙████  ██▌    ▄██▀  ██▌     ,██▀\n ██ \"██, ╙▀▀███████████⌐      ╙████████▀   ██     ╙██  ███████▀▀     ╙███████▀`\n  ██▄ ╙▀██▄▄▄▄▄,,,                ¬─                                    '─¬\n   ╙▀██▄ '╙╙╙▀▀▀▀▀▀▀▀\n      ╙▀▀██████R⌐\n */\npragma solidity 0.8.16;\n\ninterface IOndoRateLimiter {\n  enum TransactionType {\n    SUBSCRIPTION,\n    REDEMPTION\n  }\n\n  function checkAndUpdateRateLimit(\n    TransactionType transactionType,\n    address rwaToken,\n    bytes32 userID,\n    uint256 usdValue\n  ) external;\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DefaultUserRateLimitNotSet","type":"error"},{"inputs":[],"name":"GlobalRateLimitNotSet","type":"error"},{"inputs":[],"name":"RWAAddressCantBeZero","type":"error"},{"inputs":[],"name":"RateLimitExceeded","type":"error"},{"inputs":[],"name":"UserIDCantBeZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IOndoRateLimiter.TransactionType","name":"transactionType","type":"uint8"},{"indexed":false,"internalType":"address","name":"rwaToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"},{"indexed":false,"internalType":"uint48","name":"window","type":"uint48"}],"name":"DefaultUserRateLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IOndoRateLimiter.TransactionType","name":"transactionType","type":"uint8"},{"indexed":false,"internalType":"address","name":"rwaToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"},{"indexed":false,"internalType":"uint48","name":"window","type":"uint48"}],"name":"GlobalRateLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IOndoRateLimiter.TransactionType","name":"transactionType","type":"uint8"},{"indexed":false,"internalType":"address","name":"rwaToken","type":"address"},{"indexed":false,"internalType":"bytes32","name":"userID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"},{"indexed":false,"internalType":"uint48","name":"window","type":"uint48"}],"name":"UserRateLimitSet","type":"event"},{"inputs":[],"name":"CLIENT_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONFIGURER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IOndoRateLimiter.TransactionType","name":"transactionType","type":"uint8"},{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"bytes32","name":"userID","type":"bytes32"},{"internalType":"uint256","name":"usdValue","type":"uint256"}],"name":"checkAndUpdateRateLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"defaultUserRedemptionLimitConfigs","outputs":[{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"defaultUserSubscriptionLimitConfigs","outputs":[{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"}],"name":"getCurrentGlobalRedemptionLimit","outputs":[{"internalType":"uint256","name":"currentCapacityUsed","type":"uint256"},{"internalType":"uint256","name":"availableCapacity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"}],"name":"getCurrentGlobalSubscriptionLimit","outputs":[{"internalType":"uint256","name":"currentCapacityUsed","type":"uint256"},{"internalType":"uint256","name":"availableCapacity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"bytes32","name":"userID","type":"bytes32"}],"name":"getCurrentUserRedemptionLimit","outputs":[{"internalType":"uint256","name":"currentCapacityUsed","type":"uint256"},{"internalType":"uint256","name":"availableCapacity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"bytes32","name":"userID","type":"bytes32"}],"name":"getCurrentUserSubscriptionLimit","outputs":[{"internalType":"uint256","name":"currentCapacityUsed","type":"uint256"},{"internalType":"uint256","name":"availableCapacity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"globalRedemptionLimits","outputs":[{"internalType":"uint256","name":"capacityUsed","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"globalSubscriptionLimits","outputs":[{"internalType":"uint256","name":"capacityUsed","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"name":"setDefaultUserRedemptionLimitConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"name":"setDefaultUserSubscriptionLimitConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"name":"setGlobalRedemptionLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"name":"setGlobalSubscriptionLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"bytes32","name":"userID","type":"bytes32"},{"internalType":"uint256","name":"redemptionLimit","type":"uint256"},{"internalType":"uint48","name":"redemptionWindow","type":"uint48"}],"name":"setUserRedemptionRateLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rwaToken","type":"address"},{"internalType":"bytes32","name":"userID","type":"bytes32"},{"internalType":"uint256","name":"subscriptionLimit","type":"uint256"},{"internalType":"uint48","name":"subscriptionWindow","type":"uint48"}],"name":"setUserSubscriptionRateLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"userRedemptionLimits","outputs":[{"internalType":"uint256","name":"capacityUsed","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"userSubscriptionLimits","outputs":[{"internalType":"uint256","name":"capacityUsed","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint48","name":"window","type":"uint48"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0x000000000000000000000000094bee6b74ec29d32869ae3140a659cac0482882"}