ETH Price: $1,615.96 (+1.54%)
Gas: 9 Gwei
 
Transaction Hash
Method
Block
From
To
Value
Arb Restake182324092023-09-28 6:18:351 hr 14 mins ago1695881915IN
0x0865a8...5083eabF
0 ETH0.002262367.14519238
Redeem NFT182301722023-09-27 22:48:118 hrs 44 mins ago1695854891IN
0x0865a8...5083eabF
0 ETH0.001991767.48650842
Redeem NFT182235172023-09-27 0:26:471 day 7 hrs ago1695774407IN
0x0865a8...5083eabF
0 ETH0.001802277.23992644
Redeem NFT182179632023-09-26 5:46:352 days 1 hr ago1695707195IN
0x0865a8...5083eabF
0 ETH0.001615826.96935533
Redeem NFT182179082023-09-26 5:35:352 days 1 hr ago1695706535IN
0x0865a8...5083eabF
0 ETH0.001702786.28689982
Redeem NFT182122792023-09-25 10:43:112 days 20 hrs ago1695638591IN
0x0865a8...5083eabF
0 ETH0.001948048.40228496
Redeem NFT182111762023-09-25 7:00:593 days 32 mins ago1695625259IN
0x0865a8...5083eabF
0 ETH0.002341249.22670648
Redeem NFT182087692023-09-24 22:55:233 days 8 hrs ago1695596123IN
0x0865a8...5083eabF
0 ETH0.001745076.87723218
Redeem NFT182011302023-09-23 21:14:474 days 10 hrs ago1695503687IN
0x0865a8...5083eabF
0 ETH0.002035968.02360532
Redeem NFT182007282023-09-23 19:53:354 days 11 hrs ago1695498815IN
0x0865a8...5083eabF
0 ETH0.00173716.97782527
Initial Stake181999232023-09-23 17:11:594 days 14 hrs ago1695489119IN
0x0865a8...5083eabF
0 ETH0.002786667.75452409
Owner Restake181862822023-09-21 19:17:596 days 12 hrs ago1695323879IN
0x0865a8...5083eabF
0 ETH0.0067724326.08526167
Owner Restake181862812023-09-21 19:17:476 days 12 hrs ago1695323867IN
0x0865a8...5083eabF
0 ETH0.006398424.64458919
Arb Restake181681912023-09-19 6:31:479 days 1 hr ago1695105107IN
0x0865a8...5083eabF
0 ETH0.002785838.79998169
Redeem NFT181616872023-09-18 8:36:359 days 22 hrs ago1695026195IN
0x0865a8...5083eabF
0 ETH0.002124458.97814758
Redeem NFT181481522023-09-16 10:35:3511 days 20 hrs ago1694860535IN
0x0865a8...5083eabF
0 ETH0.00185468
Redeem NFT181422862023-09-15 14:43:4712 days 16 hrs ago1694789027IN
0x0865a8...5083eabF
0 ETH0.0044694517.95500746
Redeem NFT181377502023-09-14 23:24:1113 days 8 hrs ago1694733851IN
0x0865a8...5083eabF
0 ETH0.0038580915.20579396
Redeem NFT181341592023-09-14 11:15:3513 days 20 hrs ago1694690135IN
0x0865a8...5083eabF
0 ETH0.0029081212.29000046
Redeem NFT181324532023-09-14 5:31:5914 days 2 hrs ago1694669519IN
0x0865a8...5083eabF
0 ETH0.0024977210.55564377
Redeem NFT181320552023-09-14 4:11:5914 days 3 hrs ago1694664719IN
0x0865a8...5083eabF
0 ETH0.002237568.98889875
Redeem NFT181215102023-09-12 16:42:4715 days 14 hrs ago1694536967IN
0x0865a8...5083eabF
0 ETH0.0058024123.0506129
Arb Restake181088082023-09-10 22:00:1117 days 9 hrs ago1694383211IN
0x0865a8...5083eabF
0 ETH0.003107259.8152857
Initial Stake181079262023-09-10 19:01:2317 days 12 hrs ago1694372483IN
0x0865a8...5083eabF
0 ETH0.003421379.39576602
Redeem NFT180628882023-09-04 11:42:3523 days 19 hrs ago1693827755IN
0x0865a8...5083eabF
0 ETH0.0034481613.85222575
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Sherlock

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 20000 runs

Other Settings:
default evmVersion
File 1 of 28 : Sherlock.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC721/ERC721.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/security/Pausable.sol';

import './interfaces/ISherlock.sol';

/// @title Sherlock core interface for stakers
/// @author Evert Kors
// This is the contract that manages staking actions

contract Sherlock is ISherlock, ERC721, Ownable, Pausable {
  using SafeERC20 for IERC20;

  // The minimal amount needed to mint a position
  uint256 public constant MIN_STAKE = 10**6; // 1 USDC

  // The initial period for a staker to restake/withdraw without being auto-restaked
  uint256 public constant ARB_RESTAKE_WAIT_TIME = 2 weeks;

  // The period during which the reward for restaking an account (after the inital period) grows
  uint256 public constant ARB_RESTAKE_GROWTH_TIME = 1 weeks;

  // Anyone who gets auto-restaked is restaked for this period (26 weeks)
  uint256 public constant ARB_RESTAKE_PERIOD = 26 weeks;

  // The percentage of someone's stake that can be paid to an arb for restaking
  uint256 public constant ARB_RESTAKE_MAX_PERCENTAGE = (10**18 / 100) * 20; // 20%

  // USDC address
  IERC20 public immutable token;

  // SHER token address
  IERC20 public immutable sher;

  // Key is the staking period (3 months, 6 months, etc.), value will be whether it is allowed or not
  mapping(uint256 => bool) public override stakingPeriods;

  // Key is a specific position ID (NFT ID), value represents the timestamp at which the position can be unstaked/restaked
  mapping(uint256 => uint256) internal lockupEnd_;

  // Key is NFT ID, value is the amount of SHER rewards owed to that NFT position
  mapping(uint256 => uint256) internal sherRewards_;

  // Key is NFT ID, value is the amount of shares representing the USDC owed to this position (includes principal, interest, etc.)
  mapping(uint256 => uint256) internal stakeShares;

  // Total amount of shares that have been issued to all NFT positions
  uint256 internal totalStakeShares;

  // Contract representing the current yield strategy (deposits staker funds into Aave, etc.)
  IStrategyManager public override yieldStrategy;

  // Instances of relevant Sherlock contracts
  ISherDistributionManager public override sherDistributionManager;
  ISherlockProtocolManager public override sherlockProtocolManager;
  ISherlockClaimManager public override sherlockClaimManager;

  // Address to which nonstaker payments are made
  // This will start out as a multi-sig address, then become a contract address later
  address public override nonStakersAddress;

  // Stores the ID of the most recently created NFT
  // This variable is incremented by 1 to create a new NFT ID
  uint256 internal nftCounter;

  string private constant baseURI = 'https://nft.sherlock.xyz/api/mainnet/';

  // Even though `_sherDistributionManager` can be removed once deployed, every initial deployment will have an active instance.
  constructor(
    IERC20 _token, // USDC address
    IERC20 _sher, // SHER token address
    string memory _name, // Token collection name (see ERC-721 docs)
    string memory _symbol, // Token collection symbol (see ERC-721 docs)
    IStrategyManager _yieldStrategy, // The active yield strategy contract
    ISherDistributionManager _sherDistributionManager, // The active DistributionManager contract
    address _nonStakersAddress, // The address to which nonstakers payments go
    ISherlockProtocolManager _sherlockProtocolManager, // The address for the ProtocolManager contract
    ISherlockClaimManager _sherlockClaimManager, // The address for the ClaimManager contract
    uint256[] memory _initialstakingPeriods // The initial periods (3m, 6m, etc.) that someone can stake for
  ) ERC721(_name, _symbol) {
    if (address(_token) == address(0)) revert ZeroArgument();
    if (address(_sher) == address(0)) revert ZeroArgument();
    if (address(_yieldStrategy) == address(0)) revert ZeroArgument();
    if (address(_sherDistributionManager) == address(0)) revert ZeroArgument();
    if (_nonStakersAddress == address(0)) revert ZeroArgument();
    if (address(_sherlockProtocolManager) == address(0)) revert ZeroArgument();
    if (address(_sherlockClaimManager) == address(0)) revert ZeroArgument();

    token = _token;
    sher = _sher;
    yieldStrategy = _yieldStrategy;
    sherDistributionManager = _sherDistributionManager;
    nonStakersAddress = _nonStakersAddress;
    sherlockProtocolManager = _sherlockProtocolManager;
    sherlockClaimManager = _sherlockClaimManager;

    // Enabling the first set of staking periods that were provided in constructor args
    for (uint256 i; i < _initialstakingPeriods.length; i++) {
      enableStakingPeriod(_initialstakingPeriods[i]);
    }

    emit YieldStrategyUpdated(IStrategyManager(address(0)), _yieldStrategy);
    emit SherDistributionManagerUpdated(
      ISherDistributionManager(address(0)),
      _sherDistributionManager
    );
    emit NonStakerAddressUpdated(address(0), _nonStakersAddress);
    emit ProtocolManagerUpdated(ISherlockProtocolManager(address(0)), _sherlockProtocolManager);
    emit ClaimManagerUpdated(ISherlockClaimManager(address(0)), _sherlockClaimManager);
  }

  //
  // View functions
  //

  // Returns the timestamp at which the position represented by _tokenID can first be unstaked/restaked
  /// @notice View the current lockup end timestamp of `_tokenID`
  /// @return Timestamp when NFT position unlocks
  function lockupEnd(uint256 _tokenID) public view override returns (uint256) {
    if (!_exists(_tokenID)) revert NonExistent();

    return lockupEnd_[_tokenID];
  }

  // Returns the SHER rewards owed to this position
  /// @notice View the current SHER reward of `_tokenID`
  /// @return Amount of SHER rewarded to owner upon reaching the end of the lockup
  function sherRewards(uint256 _tokenID) public view override returns (uint256) {
    if (!_exists(_tokenID)) revert NonExistent();

    return sherRewards_[_tokenID];
  }

  // Returns the tokens (USDC) owed to a position
  /// @notice View the current token balance claimable upon reaching end of the lockup
  /// @return Amount of tokens assigned to owner when unstaking position
  function tokenBalanceOf(uint256 _tokenID) public view override returns (uint256) {
    if (!_exists(_tokenID)) revert NonExistent();
    // Finds the fraction of total shares owed to this position and multiplies by the total amount of tokens (USDC) owed to stakers
    return (stakeShares[_tokenID] * totalTokenBalanceStakers()) / totalStakeShares;
  }

  // Gets the total amount of tokens (USDC) owed to stakers
  // Adds this contract's balance, the tokens in the yield strategy, and the claimable premiums in the protocol manager contract
  /// @notice View the current TVL for all stakers
  /// @return Total amount of tokens staked
  /// @dev Adds principal + strategy + premiums
  /// @dev Will calculate the most up to date value for each piece
  function totalTokenBalanceStakers() public view override returns (uint256) {
    return
      token.balanceOf(address(this)) +
      yieldStrategy.balanceOf() +
      sherlockProtocolManager.claimablePremiums();
  }

  //
  // Gov functions
  //

  // Allows governance to add a new staking period (4 months, etc.)
  /// @notice Allows stakers to stake for `_period` of time
  /// @param _period Period of time, in seconds,
  /// @dev should revert if already enabled
  function enableStakingPeriod(uint256 _period) public override onlyOwner {
    if (_period == 0) revert ZeroArgument();
    // Revert if staking period is already active
    if (stakingPeriods[_period]) revert InvalidArgument();

    // Sets the staking period to true
    stakingPeriods[_period] = true;
    emit StakingPeriodEnabled(_period);
  }

  // Allows governance to remove a staking period (4 months, etc.)
  /// @notice Disallow stakers to stake for `_period` of time
  /// @param _period Period of time, in seconds,
  /// @dev should revert if already disabled
  function disableStakingPeriod(uint256 _period) external override onlyOwner {
    // Revert if staking period is already inactive
    if (!stakingPeriods[_period]) revert InvalidArgument();

    // Sets the staking period to false
    stakingPeriods[_period] = false;
    emit StakingPeriodDisabled(_period);
  }

  // Sets a new contract to be the active SHER distribution manager
  /// @notice Update SHER distribution manager contract
  /// @param _sherDistributionManager New adddress of the manager
  /// @dev After updating the contract, call setSherlockCoreAddress() on the new contract
  function updateSherDistributionManager(ISherDistributionManager _sherDistributionManager)
    external
    override
    onlyOwner
  {
    if (address(_sherDistributionManager) == address(0)) revert ZeroArgument();
    if (sherDistributionManager == _sherDistributionManager) revert InvalidArgument();

    emit SherDistributionManagerUpdated(sherDistributionManager, _sherDistributionManager);
    sherDistributionManager = _sherDistributionManager;
  }

  /// @notice Deletes the SHER distribution manager altogether (if Sherlock decides to no longer pay out SHER rewards)
  function removeSherDistributionManager() external override onlyOwner {
    if (address(sherDistributionManager) == address(0)) revert InvalidConditions();

    emit SherDistributionManagerUpdated(
      sherDistributionManager,
      ISherDistributionManager(address(0))
    );
    delete sherDistributionManager;
  }

  // Sets a new address for nonstakers payments
  /// @notice Update address eligible for non staker rewards from protocol premiums
  /// @param _nonStakers Address eligible for non staker rewards
  function updateNonStakersAddress(address _nonStakers) external override onlyOwner {
    if (address(_nonStakers) == address(0)) revert ZeroArgument();
    if (nonStakersAddress == _nonStakers) revert InvalidArgument();

    emit NonStakerAddressUpdated(nonStakersAddress, _nonStakers);
    nonStakersAddress = _nonStakers;
  }

  // Sets a new protocol manager contract
  /// @notice Transfer protocol manager implementation address
  /// @param _protocolManager new implementation address
  /// @dev After updating the contract, call setSherlockCoreAddress() on the new contract
  function updateSherlockProtocolManager(ISherlockProtocolManager _protocolManager)
    external
    override
    onlyOwner
  {
    if (address(_protocolManager) == address(0)) revert ZeroArgument();
    if (sherlockProtocolManager == _protocolManager) revert InvalidArgument();

    emit ProtocolManagerUpdated(sherlockProtocolManager, _protocolManager);
    sherlockProtocolManager = _protocolManager;
  }

  // Sets a new claim manager contract
  /// @notice Transfer claim manager role to different address
  /// @param _claimManager New address of claim manager
  /// @dev After updating the contract, call setSherlockCoreAddress() on the new contract
  function updateSherlockClaimManager(ISherlockClaimManager _claimManager)
    external
    override
    onlyOwner
  {
    if (address(_claimManager) == address(0)) revert ZeroArgument();
    if (sherlockClaimManager == _claimManager) revert InvalidArgument();

    emit ClaimManagerUpdated(sherlockClaimManager, _claimManager);
    sherlockClaimManager = _claimManager;
  }

  // Sets a new yield strategy manager contract
  /// @notice Update yield strategy
  /// @param _yieldStrategy New address of the strategy
  /// @dev Call will fail if underlying withdrawAll call fails
  /// @dev After updating the contract, call setSherlockCoreAddress() on the new contract
  function updateYieldStrategy(IStrategyManager _yieldStrategy) external override onlyOwner {
    if (address(_yieldStrategy) == address(0)) revert ZeroArgument();
    if (yieldStrategy == _yieldStrategy) revert InvalidArgument();

    yieldStrategy.withdrawAll();

    emit YieldStrategyUpdated(yieldStrategy, _yieldStrategy);
    yieldStrategy = _yieldStrategy;
  }

  // Sets a new yield strategy manager contract
  /// @notice Update yield strategy ignoring state of current strategy
  /// @param _yieldStrategy New address of the strategy
  /// @dev tries a yieldStrategyWithdrawAll() on old strategy, ignore failure
  function updateYieldStrategyForce(IStrategyManager _yieldStrategy) external override onlyOwner {
    if (address(_yieldStrategy) == address(0)) revert ZeroArgument();
    if (yieldStrategy == _yieldStrategy) revert InvalidArgument();

    // This call is surrounded with a try catch as there is a non-zero chance the underlying yield protocol(s) will fail
    // For example; the Aave V2 withdraw can fail in case there is not enough liquidity available for whatever reason.
    // In case this happens. We still want the yield strategy to be updated.
    // As the worst case could be that the Aave V2 withdraw will never work again, forcing us to never use a yield strategy ever again.
    try yieldStrategy.withdrawAll() {} catch (bytes memory reason) {
      emit YieldStrategyUpdateWithdrawAllError(reason);
    }

    emit YieldStrategyUpdated(yieldStrategy, _yieldStrategy);
    yieldStrategy = _yieldStrategy;
  }

  // Deposits a chosen amount of tokens (USDC) into the active yield strategy
  /// @notice Deposit `_amount` into active strategy
  /// @param _amount Amount of tokens
  /// @dev gov only
  function yieldStrategyDeposit(uint256 _amount) external override onlyOwner {
    if (_amount == 0) revert ZeroArgument();

    // Transfers any tokens owed to stakers from the protocol manager contract to this contract first
    sherlockProtocolManager.claimPremiumsForStakers();
    // Transfers the amount of tokens to the yield strategy contract
    token.safeTransfer(address(yieldStrategy), _amount);
    // Deposits all tokens in the yield strategy contract into the actual yield strategy
    yieldStrategy.deposit();
  }

  // Withdraws a chosen amount of tokens (USDC) from the yield strategy back into this contract
  /// @notice Withdraw `_amount` from active strategy
  /// @param _amount Amount of tokens
  /// @dev gov only
  function yieldStrategyWithdraw(uint256 _amount) external override onlyOwner {
    if (_amount == 0) revert ZeroArgument();

    yieldStrategy.withdraw(_amount);
  }

  // Withdraws all tokens from the yield strategy back into this contract
  /// @notice Withdraw all funds from active strategy
  /// @dev gov only
  function yieldStrategyWithdrawAll() external override onlyOwner {
    yieldStrategy.withdrawAll();
  }

  /// @notice Pause external functions in all contracts
  /// @dev A manager can still be replaced with a new contract in a `paused` state
  /// @dev To ensure we are still able to pause all contracts, we check if the manager is unpaused
  function pause() external onlyOwner {
    _pause();
    if (!Pausable(address(yieldStrategy)).paused()) yieldStrategy.pause();
    // sherDistributionManager can be 0, pause isn't needed in that case
    if (
      address(sherDistributionManager) != address(0) &&
      !Pausable(address(sherDistributionManager)).paused()
    ) {
      sherDistributionManager.pause();
    }
    if (!Pausable(address(sherlockProtocolManager)).paused()) sherlockProtocolManager.pause();
    if (!Pausable(address(sherlockClaimManager)).paused()) sherlockClaimManager.pause();
  }

  /// @notice Unpause external functions in all contracts
  /// @dev A manager can still be replaced with a new contract in an `unpaused` state
  /// @dev To ensure we are still able to unpause all contracts, we check if the manager is paused
  function unpause() external onlyOwner {
    _unpause();
    if (Pausable(address(yieldStrategy)).paused()) yieldStrategy.unpause();
    // sherDistributionManager can be 0, unpause isn't needed in that case
    if (
      address(sherDistributionManager) != address(0) &&
      Pausable(address(sherDistributionManager)).paused()
    ) {
      sherDistributionManager.unpause();
    }
    if (Pausable(address(sherlockProtocolManager)).paused()) sherlockProtocolManager.unpause();
    if (Pausable(address(sherlockClaimManager)).paused()) sherlockClaimManager.unpause();
  }

  //
  // Access control functions
  //
  function _beforeTokenTransfer(
    address _from,
    address _to,
    uint256 _tokenID
  ) internal override whenNotPaused {}

  function _baseURI() internal view virtual override returns (string memory) {
    return baseURI;
  }

  // Transfers specified amount of tokens to the address specified by the claim creator (protocol agent)
  // This function is called by the Sherlock claim manager contract if a claim is approved
  /// @notice Initiate a payout of `_amount` to `_receiver`
  /// @param _receiver Receiver of payout
  /// @param _amount Amount to send
  /// @dev only payout manager should call this
  /// @dev should pull money out of strategy
  function payoutClaim(address _receiver, uint256 _amount) external override whenNotPaused {
    // Can only be called by the Sherlock claim manager contract
    if (msg.sender != address(sherlockClaimManager)) revert Unauthorized();

    if (_amount != 0) {
      // Sends the amount of tokens to the receiver address (specified by the protocol agent who created the claim)
      _transferTokensOut(_receiver, _amount);
    }
    emit ClaimPayout(_receiver, _amount);
  }

  //
  // Non-access control functions
  //

  // Helper function for initial staking and restaking
  // Sets the unlock period, mints and transfers SHER tokens to this contract, assigns SHER tokens to this NFT position
  /// @notice Stakes `_amount` of tokens and locks up the `_id` position for `_period` seconds
  /// @param _amount Amount of tokens to stake
  /// @param _period Period of time for which funds get locked
  /// @param _id ID for this NFT position
  /// @param _receiver Address that will be linked to this position
  /// @return _sher Amount of SHER tokens awarded to this position after `_period` ends
  /// @dev `_period` needs to be whitelisted
  function _stake(
    uint256 _amount,
    uint256 _period,
    uint256 _id,
    address _receiver
  ) internal returns (uint256 _sher) {
    // Sets the timestamp at which this position can first be unstaked/restaked
    lockupEnd_[_id] = block.timestamp + _period;

    if (address(sherDistributionManager) == address(0)) return 0;
    // Does not allow restaking of 0 tokens
    if (_amount == 0) return 0;

    // Checks this amount of SHER tokens in this contract before we transfer new ones
    uint256 before = sher.balanceOf(address(this));

    // pullReward() calcs then actually transfers the SHER tokens to this contract
    // in case this call fails, whole (re)staking transaction fails
    _sher = sherDistributionManager.pullReward(_amount, _period, _id, _receiver);

    // actualAmount should represent the amount of SHER tokens transferred to this contract for the current stake position
    uint256 actualAmount = sher.balanceOf(address(this)) - before;
    if (actualAmount != _sher) revert InvalidSherAmount(_sher, actualAmount);
    // Assigns the newly created SHER tokens to the current stake position
    if (_sher != 0) sherRewards_[_id] = _sher;
  }

  // Checks to see if the NFT owner is the caller and that the position is unlockable
  function _verifyUnlockableByOwner(uint256 _id) internal view {
    if (ownerOf(_id) != msg.sender) revert Unauthorized();
    if (lockupEnd_[_id] > block.timestamp) revert InvalidConditions();
  }

  // Sends the SHER tokens associated with this NFT ID to the address of the NFT owner
  function _sendSherRewardsToOwner(uint256 _id, address _nftOwner) internal {
    uint256 sherReward = sherRewards_[_id];
    if (sherReward == 0) return;

    // Deletes the SHER reward mapping for this NFT ID
    delete sherRewards_[_id];

    // Transfers the SHER tokens associated with this NFT ID to the address of the NFT owner
    sher.safeTransfer(_nftOwner, sherReward);
  }

  // Transfers an amount of tokens to the receiver address
  // This is the logic for a payout AND for an unstake (used by the payoutClaim() function above and in _redeemShares() below)
  function _transferTokensOut(address _receiver, uint256 _amount) internal {
    // Transfers any premiums owed to stakers from the protocol manager to this contract
    sherlockProtocolManager.claimPremiumsForStakers();

    // The amount of tokens in this contract
    uint256 mainBalance = token.balanceOf(address(this));

    // If the amount to transfer out is still greater than the amount of tokens in this contract,
    // Withdraw yield strategy tokens to make up the difference
    if (_amount > mainBalance) {
      yieldStrategy.withdraw(_amount - mainBalance);
    }

    token.safeTransfer(_receiver, _amount);
  }

  // Returns the amount of USDC owed to this amount of stakeShares
  function _redeemSharesCalc(uint256 _stakeShares) internal view returns (uint256) {
    // Finds fraction that the given amount of stakeShares represents of the total
    // Then multiplies it by the total amount of tokens (USDC) owed to all stakers
    return (_stakeShares * totalTokenBalanceStakers()) / totalStakeShares;
  }

  // Transfers USDC to the receiver (arbitrager OR NFT owner) based on the stakeShares inputted
  // Also burns the requisite amount of shares associated with this NFT position
  // Returns the amount of USDC owed to these shares
  function _redeemShares(
    uint256 _id,
    uint256 _stakeShares,
    address _receiver
  ) internal returns (uint256 _amount) {
    // Returns the amount of USDC owed to this amount of stakeShares
    _amount = _redeemSharesCalc(_stakeShares);
    // Transfers _amount of tokens to _receiver address
    if (_amount != 0) _transferTokensOut(_receiver, _amount);

    // Subtracts this amount of stakeShares from the NFT position
    stakeShares[_id] -= _stakeShares;
    // Subtracts this amount of stakeShares from the total amount of stakeShares outstanding
    totalStakeShares -= _stakeShares;
  }

  // Helper function to restake an eligible NFT position on behalf of the NFT owner OR an arbitrager
  // Restakes an NFT position (_id) for a given period (_period) and
  // Sends any previously earned SHER rewards to the _nftOwner address
  function _restake(
    uint256 _id,
    uint256 _period,
    address _nftOwner
  ) internal returns (uint256 _sher) {
    // Sends the SHER tokens previously earned by this NFT ID to the address of the NFT owner
    // NOTE This function deletes the SHER reward mapping for this NFT ID
    _sendSherRewardsToOwner(_id, _nftOwner);

    // tokenBalanceOf() returns the USDC amount owed to this NFT ID
    // _stake() restakes that amount of USDC for the period inputted
    // We use the same ID that we just deleted the SHER rewards mapping for
    // Resets the lockupEnd mapping and SHER token rewards mapping for this ID
    // Note stakeShares for this position do not change so no need to update
    _sher = _stake(tokenBalanceOf(_id), _period, _id, _nftOwner);

    emit Restaked(_id);
  }

  // This function is called in the UI by anyone who is staking for the first time (not restaking a previous position)
  /// @notice Stakes `_amount` of tokens and locks up for `_period` seconds, `_receiver` will receive the NFT receipt
  /// @param _amount Amount of tokens to stake
  /// @param _period Period of time, in seconds, to lockup your funds
  /// @param _receiver Address that will receive the NFT representing the position
  /// @return _id ID of the position
  /// @return _sher Amount of SHER tokens to be released to this ID after `_period` ends
  /// @dev `_period` needs to be whitelisted
  function initialStake(
    uint256 _amount,
    uint256 _period,
    address _receiver
  ) external override whenNotPaused returns (uint256 _id, uint256 _sher) {
    if (_amount == 0) revert ZeroArgument();
    if (_amount < MIN_STAKE) revert InvalidArgument();
    // Makes sure the period is a whitelisted period
    if (!stakingPeriods[_period]) revert InvalidArgument();
    if (address(_receiver) == address(0)) revert ZeroArgument();
    // Adds 1 to the ID of the last NFT created for the new NFT ID
    _id = ++nftCounter;

    // Transfers the USDC from the msg.sender to this contract for the amount specified (this is the staking action)
    token.safeTransferFrom(msg.sender, address(this), _amount);

    uint256 stakeShares_;
    uint256 totalStakeShares_ = totalStakeShares;
    // _amount of tokens divided by the "before" total amount of tokens, multiplied by the "before" amount of stake shares
    if (totalStakeShares_ != 0)
      stakeShares_ = (_amount * totalStakeShares_) / (totalTokenBalanceStakers() - _amount);
      // If this is the first stake ever, we just mint stake shares equal to the amount of USDC staked
    else stakeShares_ = _amount;

    // Assigns this NFT ID the calc'd amount of stake shares above
    stakeShares[_id] = stakeShares_;
    // Adds the newly created stake shares to the total amount of stake shares
    totalStakeShares += stakeShares_;

    // Locks up the USDC amount and calcs the SHER token amount to receive on unstake
    _sher = _stake(_amount, _period, _id, _receiver);

    // This is an ERC-721 function that creates an NFT and sends it to the receiver
    _safeMint(_receiver, _id);
  }

  // This is how a staker unstakes and cashes out on their position
  /// @notice Redeem NFT `_id` and receive `_amount` of tokens
  /// @param _id TokenID of the position
  /// @return _amount Amount of tokens (USDC) owed to NFT ID
  /// @dev Only the owner of `_id` will be able to redeem their position
  /// @dev The SHER rewards are sent to the NFT owner
  /// @dev Can only be called after lockup `_period` has ended
  function redeemNFT(uint256 _id) external override whenNotPaused returns (uint256 _amount) {
    // Checks to make sure caller is the owner of the NFT position, and that the lockup period is over
    _verifyUnlockableByOwner(_id);

    // This is the ERC-721 function to destroy an NFT (with owner's approval)
    _burn(_id);

    // Transfers USDC to the NFT owner based on the stake shares associated with this NFT ID
    // Also burns the requisite amount of shares associated with this NFT position
    // Returns the amount of USDC owed to these shares
    _amount = _redeemShares(_id, stakeShares[_id], msg.sender);

    // Sends the SHER tokens associated with this NFT ID to the NFT owner
    _sendSherRewardsToOwner(_id, msg.sender);

    // Removes the unlock deadline associated with this NFT
    delete lockupEnd_[_id];
  }

  // This is how a staker restakes an expired position
  /// @notice Owner restakes position with ID: `_id` for `_period` seconds
  /// @param _id ID of the position
  /// @param _period Period of time, in seconds, to lockup your funds
  /// @return _sher Amount of SHER tokens to be released to owner address after `_period` ends
  /// @dev Only the owner of `_id` will be able to restake their position using this call
  /// @dev `_period` needs to be whitelisted
  /// @dev Can only be called after lockup `_period` has ended
  function ownerRestake(uint256 _id, uint256 _period)
    external
    override
    whenNotPaused
    returns (uint256 _sher)
  {
    // Checks to make sure caller is the owner of the NFT position, and that the lockup period is over
    _verifyUnlockableByOwner(_id);

    // Checks to make sure the staking period is a whitelisted one
    if (!stakingPeriods[_period]) revert InvalidArgument();

    // Sends the previously earned SHER token rewards to the owner and restakes the USDC value of the position
    _sher = _restake(_id, _period, msg.sender);
  }

  // Calcs the reward (in stake shares) an arb would get for restaking a position
  // Takes the NFT ID as a param and outputs the stake shares (which can be redeemed for USDC) for the arb
  function _calcSharesForArbRestake(uint256 _id) internal view returns (uint256, bool) {
    // this is the first point at which an arb can restake a position (i.e. two weeks after the initial lockup ends)
    uint256 initialArbTime = lockupEnd_[_id] + ARB_RESTAKE_WAIT_TIME;

    // If the initialArbTime has not passed, return 0 for the stake shares and false for whether an arb can restake the position
    if (initialArbTime > block.timestamp) return (0, false);

    // The max rewards (as a % of the position's shares) for the arb are available at this timestamp
    uint256 maxRewardArbTime = initialArbTime + ARB_RESTAKE_GROWTH_TIME;

    // Caps the timestamp at the maxRewardArbTime so the calc below never goes above 100%
    uint256 targetTime = block.timestamp < maxRewardArbTime ? block.timestamp : maxRewardArbTime;

    // Scaled by 10**18
    // Represents the max amount of stake shares that an arb could get from restaking this position
    uint256 maxRewardScaled = ARB_RESTAKE_MAX_PERCENTAGE * stakeShares[_id];

    // Calcs what % of the max reward an arb gets based on the timestamp at which they call this function
    // If targetTime == maxRewardArbTime, then the arb gets 100% of the maxRewardScaled
    return (
      ((targetTime - initialArbTime) * maxRewardScaled) / (ARB_RESTAKE_GROWTH_TIME) / 10**18,
      true
    );
  }

  /// @notice Calculates the reward in tokens (USDC) that an arb would get for calling restake on a position
  /// @return profit How much profit an arb would make in USDC
  /// @return able If the transaction can be executed (the current timestamp is during an arb period, etc.)
  function viewRewardForArbRestake(uint256 _id) external view returns (uint256 profit, bool able) {
    if (!_exists(_id)) revert NonExistent();
    // Returns the stake shares that an arb would get, and whether the position can currently be arbed
    // `profit` variable is used to store the amount of shares
    (profit, able) = _calcSharesForArbRestake(_id);
    // Calculates the tokens (USDC) represented by that amount of stake shares
    // Amount of shares stored in `profit` is used to calculate the reward in USDC, which is stored in `profit`
    profit = _redeemSharesCalc(profit);
  }

  /// @notice Allows someone who doesn't own the position (an arbitrager) to restake the position for 26 weeks (ARB_RESTAKE_PERIOD)
  /// @param _id ID of the position
  /// @return _sher Amount of SHER tokens to be released to position owner on expiry of the 26 weeks lockup
  /// @return _arbReward Amount of tokens (USDC) sent to caller (the arbitrager) in return for calling the function
  /// @dev Can only be called after lockup `_period` is more than 2 weeks in the past (assuming ARB_RESTAKE_WAIT_TIME is 2 weeks)
  /// @dev Max 20% (ARB_RESTAKE_MAX_PERCENTAGE) of tokens associated with a position are used to incentivize arbs (x)
  /// @dev During a 2 week period the reward ratio will move from 0% to 100% (* x)
  function arbRestake(uint256 _id)
    external
    override
    whenNotPaused
    returns (uint256 _sher, uint256 _arbReward)
  {
    address nftOwner = ownerOf(_id);

    // Returns the stake shares that an arb would get, and whether the position can currently be arbed
    (uint256 arbRewardShares, bool able) = _calcSharesForArbRestake(_id);
    // Revert if not able to be arbed
    if (!able) revert InvalidConditions();

    // Transfers USDC to the arbitrager based on the stake shares associated with the arb reward
    // Also burns the requisite amount of shares associated with this NFT position
    // Returns the amount of USDC paid to the arbitrager
    _arbReward = _redeemShares(_id, arbRewardShares, msg.sender);

    // Restakes the tokens (USDC) associated with this position for the ARB_RESTAKE_PERIOD (26 weeks)
    // Sends previously earned SHER rewards to the NFT owner address
    _sher = _restake(_id, ARB_RESTAKE_PERIOD, nftOwner);

    emit ArbRestaked(_id, _arbReward);
  }
}

File 2 of 28 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

File 3 of 28 : ERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/ERC721.sol)

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits a {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC721: approve to caller");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
}

File 4 of 28 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

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

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

File 5 of 28 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

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

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

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

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 6 of 28 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 7 of 28 : ISherlock.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import './ISherlockStake.sol';
import './ISherlockGov.sol';
import './ISherlockPayout.sol';
import './ISherlockStrategy.sol';

interface ISherlock is ISherlockStake, ISherlockGov, ISherlockPayout, ISherlockStrategy, IERC721 {
  // msg.sender is not authorized to call this function
  error Unauthorized();

  // An address or other value passed in is equal to zero (and shouldn't be)
  error ZeroArgument();

  // Occurs when a value already holds the desired property, or is not whitelisted
  error InvalidArgument();

  // Required conditions are not true/met
  error InvalidConditions();

  // If the SHER tokens held in a contract are not the value they are supposed to be
  error InvalidSherAmount(uint256 expected, uint256 actual);

  // Checks the ERC-721 functions _exists() to see if an NFT ID actually exists and errors if not
  error NonExistent();

  event ArbRestaked(uint256 indexed tokenID, uint256 reward);

  event Restaked(uint256 indexed tokenID);
}

File 8 of 28 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}

File 9 of 28 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 10 of 28 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

File 11 of 28 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

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

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

File 13 of 28 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

File 14 of 28 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 15 of 28 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

File 16 of 28 : ISherlockStake.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

/// @title Sherlock core interface for stakers
/// @author Evert Kors
interface ISherlockStake {
  /// @notice View the current lockup end timestamp of `_tokenID`
  /// @return Timestamp when NFT position unlocks
  function lockupEnd(uint256 _tokenID) external view returns (uint256);

  /// @notice View the current SHER reward of `_tokenID`
  /// @return Amount of SHER rewarded to owner upon reaching the end of the lockup
  function sherRewards(uint256 _tokenID) external view returns (uint256);

  /// @notice View the current token balance claimable upon reaching end of the lockup
  /// @return Amount of tokens assigned to owner when unstaking position
  function tokenBalanceOf(uint256 _tokenID) external view returns (uint256);

  /// @notice View the current TVL for all stakers
  /// @return Total amount of tokens staked
  /// @dev Adds principal + strategy + premiums
  /// @dev Will calculate the most up to date value for each piece
  function totalTokenBalanceStakers() external view returns (uint256);

  /// @notice Stakes `_amount` of tokens and locks up for `_period` seconds, `_receiver` will receive the NFT receipt
  /// @param _amount Amount of tokens to stake
  /// @param _period Period of time, in seconds, to lockup your funds
  /// @param _receiver Address that will receive the NFT representing the position
  /// @return _id ID of the position
  /// @return _sher Amount of SHER tokens to be released to this ID after `_period` ends
  /// @dev `_period` needs to be whitelisted
  function initialStake(
    uint256 _amount,
    uint256 _period,
    address _receiver
  ) external returns (uint256 _id, uint256 _sher);

  /// @notice Redeem NFT `_id` and receive `_amount` of tokens
  /// @param _id TokenID of the position
  /// @return _amount Amount of tokens (USDC) owed to NFT ID
  /// @dev Only the owner of `_id` will be able to redeem their position
  /// @dev The SHER rewards are sent to the NFT owner
  /// @dev Can only be called after lockup `_period` has ended
  function redeemNFT(uint256 _id) external returns (uint256 _amount);

  /// @notice Owner restakes position with ID: `_id` for `_period` seconds
  /// @param _id ID of the position
  /// @param _period Period of time, in seconds, to lockup your funds
  /// @return _sher Amount of SHER tokens to be released to owner address after `_period` ends
  /// @dev Only the owner of `_id` will be able to restake their position using this call
  /// @dev `_period` needs to be whitelisted
  /// @dev Can only be called after lockup `_period` has ended
  function ownerRestake(uint256 _id, uint256 _period) external returns (uint256 _sher);

  /// @notice Allows someone who doesn't own the position (an arbitrager) to restake the position for 26 weeks (ARB_RESTAKE_PERIOD)
  /// @param _id ID of the position
  /// @return _sher Amount of SHER tokens to be released to position owner on expiry of the 26 weeks lockup
  /// @return _arbReward Amount of tokens (USDC) sent to caller (the arbitrager) in return for calling the function
  /// @dev Can only be called after lockup `_period` is more than 2 weeks in the past (assuming ARB_RESTAKE_WAIT_TIME is 2 weeks)
  /// @dev Max 20% (ARB_RESTAKE_MAX_PERCENTAGE) of tokens associated with a position are used to incentivize arbs (x)
  /// @dev During a 2 week period the reward ratio will move from 0% to 100% (* x)
  function arbRestake(uint256 _id) external returns (uint256 _sher, uint256 _arbReward);
}

File 17 of 28 : ISherlockGov.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import './managers/ISherDistributionManager.sol';
import './managers/ISherlockProtocolManager.sol';
import './managers/ISherlockClaimManager.sol';
import './managers/IStrategyManager.sol';

/// @title Sherlock core interface for governance
/// @author Evert Kors
interface ISherlockGov {
  event ClaimPayout(address receiver, uint256 amount);
  event YieldStrategyUpdateWithdrawAllError(bytes error);
  event YieldStrategyUpdated(IStrategyManager previous, IStrategyManager current);
  event ProtocolManagerUpdated(ISherlockProtocolManager previous, ISherlockProtocolManager current);
  event ClaimManagerUpdated(ISherlockClaimManager previous, ISherlockClaimManager current);
  event NonStakerAddressUpdated(address previous, address current);
  event SherDistributionManagerUpdated(
    ISherDistributionManager previous,
    ISherDistributionManager current
  );

  event StakingPeriodEnabled(uint256 period);

  event StakingPeriodDisabled(uint256 period);

  /// @notice Allows stakers to stake for `_period` of time
  /// @param _period Period of time, in seconds,
  /// @dev should revert if already enabled
  function enableStakingPeriod(uint256 _period) external;

  /// @notice Disallow stakers to stake for `_period` of time
  /// @param _period Period of time, in seconds,
  /// @dev should revert if already disabled
  function disableStakingPeriod(uint256 _period) external;

  /// @notice View if `_period` is a valid period
  /// @return Boolean indicating if period is valid
  function stakingPeriods(uint256 _period) external view returns (bool);

  /// @notice Update SHER distribution manager contract
  /// @param _sherDistributionManager New adddress of the manager
  function updateSherDistributionManager(ISherDistributionManager _sherDistributionManager)
    external;

  /// @notice Deletes the SHER distribution manager altogether (if Sherlock decides to no longer pay out SHER rewards)
  function removeSherDistributionManager() external;

  /// @notice Read SHER distribution manager
  /// @return Address of current SHER distribution manager
  function sherDistributionManager() external view returns (ISherDistributionManager);

  /// @notice Update address eligible for non staker rewards from protocol premiums
  /// @param _nonStakers Address eligible for non staker rewards
  function updateNonStakersAddress(address _nonStakers) external;

  /// @notice View current non stakers address
  /// @return Current non staker address
  /// @dev Is able to pull funds out of the contract
  function nonStakersAddress() external view returns (address);

  /// @notice View current address able to manage protocols
  /// @return Protocol manager implemenation
  function sherlockProtocolManager() external view returns (ISherlockProtocolManager);

  /// @notice Transfer protocol manager implementation address
  /// @param _protocolManager new implementation address
  function updateSherlockProtocolManager(ISherlockProtocolManager _protocolManager) external;

  /// @notice View current address able to pull payouts
  /// @return Address able to pull payouts
  function sherlockClaimManager() external view returns (ISherlockClaimManager);

  /// @notice Transfer claim manager role to different address
  /// @param _claimManager New address of claim manager
  function updateSherlockClaimManager(ISherlockClaimManager _claimManager) external;

  /// @notice Update yield strategy
  /// @param _yieldStrategy New address of the strategy
  /// @dev try a yieldStrategyWithdrawAll() on old, ignore failure
  function updateYieldStrategy(IStrategyManager _yieldStrategy) external;

  /// @notice Update yield strategy ignoring current state
  /// @param _yieldStrategy New address of the strategy
  /// @dev tries a yieldStrategyWithdrawAll() on old strategy, ignore failure
  function updateYieldStrategyForce(IStrategyManager _yieldStrategy) external;

  /// @notice Read current strategy
  /// @return Address of current strategy
  /// @dev can never be address(0)
  function yieldStrategy() external view returns (IStrategyManager);
}

File 18 of 28 : ISherlockPayout.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

/// @title Sherlock interface for payout manager
/// @author Evert Kors
interface ISherlockPayout {
  /// @notice Initiate a payout of `_amount` to `_receiver`
  /// @param _receiver Receiver of payout
  /// @param _amount Amount to send
  /// @dev only payout manager should call this
  /// @dev should pull money out of strategy
  function payoutClaim(address _receiver, uint256 _amount) external;
}

File 19 of 28 : ISherlockStrategy.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import './managers/IStrategyManager.sol';

/// @title Sherlock core interface for yield strategy
/// @author Evert Kors
interface ISherlockStrategy {
  /// @notice Deposit `_amount` into active strategy
  /// @param _amount Amount of tokens
  /// @dev gov only
  function yieldStrategyDeposit(uint256 _amount) external;

  /// @notice Withdraw `_amount` from active strategy
  /// @param _amount Amount of tokens
  /// @dev gov only
  function yieldStrategyWithdraw(uint256 _amount) external;

  /// @notice Withdraw all funds from active strategy
  /// @dev gov only
  function yieldStrategyWithdrawAll() external;
}

File 20 of 28 : ISherDistributionManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import './IManager.sol';

interface ISherDistributionManager is IManager {
  // anyone can just send token to this contract to fund rewards

  event Initialized(uint256 maxRewardsEndTVL, uint256 zeroRewardsStartTVL, uint256 maxRewardRate);

  /// @notice Caller will receive `_sher` SHER tokens based on `_amount` and `_period`
  /// @param _amount Amount of tokens (in USDC) staked
  /// @param _period Period of time for stake, in seconds
  /// @param _id ID for this NFT position
  /// @param _receiver Address that will be linked to this position
  /// @return _sher Amount of SHER tokens sent to Sherlock core contract
  /// @dev Calling contract will depend on before + after balance diff and return value
  /// @dev INCLUDES stake in calculation, function expects the `_amount` to be deposited already
  /// @dev If tvl=50 and amount=50, this means it is calculating SHER rewards for the first 50 tokens going in
  function pullReward(
    uint256 _amount,
    uint256 _period,
    uint256 _id,
    address _receiver
  ) external returns (uint256 _sher);

  /// @notice Calculates how many `_sher` SHER tokens are owed to a stake position based on `_amount` and `_period`
  /// @param _tvl TVL to use for reward calculation (pre-stake TVL)
  /// @param _amount Amount of tokens (USDC) staked
  /// @param _period Stake period (in seconds)
  /// @return _sher Amount of SHER tokens owed to this stake position
  /// @dev EXCLUDES `_amount` of stake, this will be added on top of TVL (_tvl is excluding _amount)
  /// @dev If tvl=0 and amount=50, it would calculate for the first 50 tokens going in (different from pullReward())
  function calcReward(
    uint256 _tvl,
    uint256 _amount,
    uint256 _period
  ) external view returns (uint256 _sher);

  /// @notice Function used to check if this is the current active distribution manager
  /// @return Boolean indicating it's active
  /// @dev If inactive the owner can pull all ERC20s and ETH
  /// @dev Will be checked by calling the sherlock contract
  function isActive() external view returns (bool);
}

File 21 of 28 : ISherlockProtocolManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import './IManager.sol';

/// @title Sherlock core interface for protocols
/// @author Evert Kors
interface ISherlockProtocolManager is IManager {
  // msg.sender is not authorized to call this function
  error Unauthorized();

  // If a protocol was never instantiated or was removed and the claim deadline has passed, this error is returned
  error ProtocolNotExists(bytes32 protocol);

  // When comparing two arrays and the lengths are not equal (but are supposed to be equal)
  error UnequalArrayLength();

  // If there is not enough balance in the contract for the amount requested (after any requirements are met), this is returned
  error InsufficientBalance(bytes32 protocol);

  event MinBalance(uint256 previous, uint256 current);

  event AccountingError(bytes32 indexed protocol, uint256 amount, uint256 insufficientTokens);

  event ProtocolAdded(bytes32 indexed protocol);

  event ProtocolRemovedByArb(bytes32 indexed protocol, address arb, uint256 profit);

  event ProtocolRemoved(bytes32 indexed protocol);

  event ProtocolUpdated(
    bytes32 indexed protocol,
    bytes32 coverage,
    uint256 nonStakers,
    uint256 coverageAmount
  );

  event ProtocolAgentTransfer(bytes32 indexed protocol, address from, address to);

  event ProtocolBalanceDeposited(bytes32 indexed protocol, uint256 amount);

  event ProtocolBalanceWithdrawn(bytes32 indexed protocol, uint256 amount);

  event ProtocolPremiumChanged(bytes32 indexed protocol, uint256 oldPremium, uint256 newPremium);

  /// @notice View current amount of all premiums that are owed to stakers
  /// @return Premiums claimable
  /// @dev Will increase every block
  /// @dev base + (now - last_settled) * ps
  function claimablePremiums() external view returns (uint256);

  /// @notice Transfer current claimable premiums (for stakers) to core Sherlock address
  /// @dev Callable by everyone
  /// @dev Funds will be transferred to Sherlock core contract
  function claimPremiumsForStakers() external;

  /// @notice View current protocolAgent of `_protocol`
  /// @param _protocol Protocol identifier
  /// @return Address able to submit claims
  function protocolAgent(bytes32 _protocol) external view returns (address);

  /// @notice View current premium of protocol
  /// @param _protocol Protocol identifier
  /// @return Amount of premium `_protocol` pays per second
  function premium(bytes32 _protocol) external view returns (uint256);

  /// @notice View current active balance of covered protocol
  /// @param _protocol Protocol identifier
  /// @return Active balance
  /// @dev Accrued debt is subtracted from the stored active balance
  function activeBalance(bytes32 _protocol) external view returns (uint256);

  /// @notice View seconds of coverage left for `_protocol` before it runs out of active balance
  /// @param _protocol Protocol identifier
  /// @return Seconds of coverage left
  function secondsOfCoverageLeft(bytes32 _protocol) external view returns (uint256);

  /// @notice Add a new protocol to Sherlock
  /// @param _protocol Protocol identifier
  /// @param _protocolAgent Address able to submit a claim on behalf of the protocol
  /// @param _coverage Hash referencing the active coverage agreement
  /// @param _nonStakers Percentage of premium payments to nonstakers, scaled by 10**18
  /// @param _coverageAmount Max amount claimable by this protocol
  /// @dev Adding a protocol allows the `_protocolAgent` to submit a claim
  /// @dev Coverage is not started yet as the protocol doesn't pay a premium at this point
  /// @dev `_nonStakers` is scaled by 10**18
  /// @dev Only callable by governance
  function protocolAdd(
    bytes32 _protocol,
    address _protocolAgent,
    bytes32 _coverage,
    uint256 _nonStakers,
    uint256 _coverageAmount
  ) external;

  /// @notice Update info regarding a protocol
  /// @param _protocol Protocol identifier
  /// @param _coverage Hash referencing the active coverage agreement
  /// @param _nonStakers Percentage of premium payments to nonstakers, scaled by 10**18
  /// @param _coverageAmount Max amount claimable by this protocol
  /// @dev Only callable by governance
  function protocolUpdate(
    bytes32 _protocol,
    bytes32 _coverage,
    uint256 _nonStakers,
    uint256 _coverageAmount
  ) external;

  /// @notice Remove a protocol from coverage
  /// @param _protocol Protocol identifier
  /// @dev Before removing a protocol the premium must be 0
  /// @dev Removing a protocol basically stops the `_protocolAgent` from being active (can still submit claims until claim deadline though)
  /// @dev Pays off debt + sends remaining balance to protocol agent
  /// @dev This call should be subject to a timelock
  /// @dev Only callable by governance
  function protocolRemove(bytes32 _protocol) external;

  /// @notice Remove a protocol with insufficient active balance
  /// @param _protocol Protocol identifier
  function forceRemoveByActiveBalance(bytes32 _protocol) external;

  /// @notice Removes a protocol with insufficent seconds of coverage left
  /// @param _protocol Protocol identifier
  function forceRemoveBySecondsOfCoverage(bytes32 _protocol) external;

  /// @notice View minimal balance needed before liquidation can start
  /// @return Minimal balance needed
  function minActiveBalance() external view returns (uint256);

  /// @notice Sets the minimum active balance before an arb can remove a protocol
  /// @param _minActiveBalance Minimum balance needed (in USDC)
  /// @dev Only gov
  function setMinActiveBalance(uint256 _minActiveBalance) external;

  /// @notice Set premium of `_protocol` to `_premium`
  /// @param _protocol Protocol identifier
  /// @param _premium Amount of premium `_protocol` pays per second
  /// @dev The value 0 would mean inactive coverage
  /// @dev Only callable by governance
  function setProtocolPremium(bytes32 _protocol, uint256 _premium) external;

  /// @notice Set premium of multiple protocols
  /// @param _protocol Array of protocol identifiers
  /// @param _premium Array of premium amounts protocols pay per second
  /// @dev The value 0 would mean inactive coverage
  /// @dev Only callable by governance
  function setProtocolPremiums(bytes32[] calldata _protocol, uint256[] calldata _premium) external;

  /// @notice Deposits `_amount` of token to the active balance of `_protocol`
  /// @param _protocol Protocol identifier
  /// @param _amount Amount of tokens to deposit
  /// @dev Approval should be made before calling
  function depositToActiveBalance(bytes32 _protocol, uint256 _amount) external;

  /// @notice Withdraws `_amount` of token from the active balance of `_protocol`
  /// @param _protocol Protocol identifier
  /// @param _amount Amount of tokens to withdraw
  /// @dev Only protocol agent is able to withdraw
  /// @dev Balance can be withdrawn up until 7 days worth of active balance
  function withdrawActiveBalance(bytes32 _protocol, uint256 _amount) external;

  /// @notice Transfer protocol agent role
  /// @param _protocol Protocol identifier
  /// @param _protocolAgent Account able to submit a claim on behalf of the protocol
  /// @dev Only the active protocolAgent is able to transfer the role
  function transferProtocolAgent(bytes32 _protocol, address _protocolAgent) external;

  /// @notice View the amount nonstakers can claim from this protocol
  /// @param _protocol Protocol identifier
  /// @return Amount of tokens claimable by nonstakers
  /// @dev this reads from a storage variable + (now-lastsettled) * premiums
  function nonStakersClaimable(bytes32 _protocol) external view returns (uint256);

  /// @notice Choose an `_amount` of tokens that nonstakers (`_receiver` address) will receive from `_protocol`
  /// @param _protocol Protocol identifier
  /// @param _amount Amount of tokens
  /// @param _receiver Address to receive tokens
  /// @dev Only callable by nonstakers role
  function nonStakersClaim(
    bytes32 _protocol,
    uint256 _amount,
    address _receiver
  ) external;

  /// @param _protocol Protocol identifier
  /// @return current and previous are the current and previous coverage amounts for this protocol
  function coverageAmounts(bytes32 _protocol)
    external
    view
    returns (uint256 current, uint256 previous);

  /// @notice Function used to check if this is the current active protocol manager
  /// @return Boolean indicating it's active
  /// @dev If inactive the owner can pull all ERC20s and ETH
  /// @dev Will be checked by calling the sherlock contract
  function isActive() external view returns (bool);
}

File 22 of 28 : ISherlockClaimManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

import './callbacks/ISherlockClaimManagerCallbackReceiver.sol';
import '../UMAprotocol/OptimisticRequester.sol';
import './IManager.sol';

interface ISherlockClaimManager is IManager, OptimisticRequester {
  // Doesn't allow a new claim to be submitted by a protocol agent if a claim is already active for that protocol
  error ClaimActive();

  // If the current state of a claim does not match the expected state, this error is thrown
  error InvalidState();

  event ClaimCreated(
    uint256 claimID,
    bytes32 indexed protocol,
    uint256 amount,
    address receiver,
    bool previousCoverageUsed
  );

  event CallbackAdded(ISherlockClaimManagerCallbackReceiver callback);

  event CallbackRemoved(ISherlockClaimManagerCallbackReceiver callback);

  event ClaimStatusChanged(uint256 indexed claimID, State previousState, State currentState);

  event ClaimPayout(uint256 claimID, address receiver, uint256 amount);

  event ClaimHalted(uint256 claimID);

  event UMAHORenounced();

  enum State {
    NonExistent, // Claim doesn't exist (this is the default state on creation)
    SpccPending, // Claim is created, SPCC is able to set state to valid
    SpccApproved, // Final state, claim is valid
    SpccDenied, // Claim denied by SPCC, claim can be escalated within 4 weeks
    UmaPriceProposed, // Price is proposed but not escalated
    ReadyToProposeUmaDispute, // Price is proposed, callback received, ready to submit dispute
    UmaDisputeProposed, // Escalation is done, waiting for confirmation
    UmaPending, // Claim is escalated, in case Spcc denied or didn't act within 7 days.
    UmaApproved, // Final state, claim is valid, claim can be enacted after 1 day, umaHaltOperator has 1 day to change to denied
    UmaDenied, // Final state, claim is invalid
    Halted, // UMAHO can halt claim if state is UmaApproved
    Cleaned // Claim is removed by protocol agent
  }

  struct Claim {
    uint256 created;
    uint256 updated;
    address initiator;
    bytes32 protocol;
    uint256 amount;
    address receiver;
    uint32 timestamp;
    State state;
    bytes ancillaryData;
  }

  // requestAndProposePriceFor() --> proposer = sherlockCore (address to receive BOND if UMA denies claim)
  // disputePriceFor() --> disputer = protocolAgent
  // priceSettled will be the the callback that contains the main data

  // Assume BOND = 9600, UMA's final fee = 1500.
  // Claim initiator (Sherlock) has to pay 22.2k to dispute a claim,
  // so we will execute a safeTransferFrom(claimInitiator, address(this), 22.2k).
  // We need to approve the contract 22.2k as it will be transferred from address(this).

  // The 22.2k consists of 2 * (BOND + final fee charged by UMA), as follows:
  // 1. On requestAndProposePriceFor(), the fee will be 10k: 9600 BOND + 1500 UMA's final fee;
  // 2. On disputePriceFor(), the fee will be the same 10k.
  // note that half of the BOND (4800) + UMA's final fee (1500) is "burnt" and sent to UMA

  // UMA's final fee can be changed in the future, which may result in lower or higher required staked amounts for escalating a claim.

  // On settle, either the protocolAgent (dispute success) or sherlockCore (dispute failure)
  // will receive 9600 + 4800 + 1500 = 15900. In addition, the protocolAgent will be entitled to
  // the claimAmount if the dispute is successful/

  // lastClaimID <-- starts with 0, so initial id = 1
  // have claim counter, easy to identify certain claims by their number
  // but use hash(callback.request.propose + callback.timestamp) as the internal UUID to handle the callbacks

  // So SPCC and UMAHO are hardcoded (UMAHO can be renounced)
  // In case these need to be updated, deploy different contract and upgrade it on the sherlock gov side.

  // On price proposed callback --> call disputePriceFor with callbackdata + sherlock.strategyManager() and address(this)

  /// @notice `SHERLOCK_CLAIM` in utf8
  function UMA_IDENTIFIER() external view returns (bytes32);

  function sherlockProtocolClaimsCommittee() external view returns (address);

  /// @notice operator is able to deny approved UMA claims
  function umaHaltOperator() external view returns (address);

  /// @notice gov is able to renounce the role
  function renounceUmaHaltOperator() external;

  function claim(uint256 _claimID) external view returns (Claim memory);

  /// @notice Initiate a claim for a specific protocol as the protocol agent
  /// @param _protocol protocol ID (different from the internal or public claim ID fields)
  /// @param _amount amount of USDC which is being claimed by the protocol
  /// @param _receiver address to receive the amount of USDC being claimed
  /// @param _timestamp timestamp at which the exploit first occurred
  /// @param ancillaryData other data associated with the claim, such as the coverage agreement
  /// @dev The protocol agent that starts a claim will be the protocol agent during the claims lifecycle
  /// @dev Even if the protocol agent role is tranferred during the lifecycle
  function startClaim(
    bytes32 _protocol,
    uint256 _amount,
    address _receiver,
    uint32 _timestamp,
    bytes memory ancillaryData
  ) external;

  function spccApprove(uint256 _claimID) external;

  function spccRefuse(uint256 _claimID) external;

  /// @notice Callable by protocol agent
  /// @param _claimID Public claim ID
  /// @param _amount Bond amount sent by protocol agent
  /// @dev Use hardcoded USDC address
  /// @dev Use hardcoded bond amount
  /// @dev Use hardcoded liveness 7200 (2 hours)
  /// @dev proposedPrice = _amount
  function escalate(uint256 _claimID, uint256 _amount) external;

  /// @notice Execute claim, storage will be removed after
  /// @param _claimID Public ID of the claim
  /// @dev Needs to be SpccApproved or UmaApproved && >UMAHO_TIME
  /// @dev Funds will be pulled from core
  function payoutClaim(uint256 _claimID) external;

  /// @notice UMAHO is able to execute a halt if the state is UmaApproved and state was updated less than UMAHO_TIME ago
  function executeHalt(uint256 _claimID) external;
}

File 23 of 28 : IStrategyManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import './IManager.sol';

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

interface IStrategyManager is IManager {
  /// @return Returns the token type being deposited into a strategy
  function want() external view returns (IERC20);

  /// @notice Withdraws all USDC from the strategy back into the Sherlock core contract
  /// @dev Only callable by the Sherlock core contract
  /// @return The final amount withdrawn
  function withdrawAll() external returns (uint256);

  /// @notice Withdraws a specific amount of USDC from the strategy back into the Sherlock core contract
  /// @param _amount Amount of USDC to withdraw
  function withdraw(uint256 _amount) external;

  /// @notice Deposits all USDC held in this contract into the strategy
  function deposit() external;

  /// @return Returns the USDC balance in this contract
  function balanceOf() external view returns (uint256);
}

File 24 of 28 : IManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

import '../ISherlock.sol';

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

interface IManager {
  // An address or other value passed in is equal to zero (and shouldn't be)
  error ZeroArgument();

  // Occurs when a value already holds the desired property, or is not whitelisted
  error InvalidArgument();

  // If a required condition for executing the function is not met, it reverts and throws this error
  error InvalidConditions();

  // Throws if the msg.sender is not the required address
  error InvalidSender();

  event SherlockCoreSet(ISherlock sherlock);

  /// @notice Set sherlock core address where premiums should be send too
  /// @param _sherlock Current core contract
  /// @dev Only deployer is able to set core address on all chains except Hardhat network
  /// @dev One time function, will revert once `sherlock` != address(0)
  /// @dev This contract will be deployed first, passed on as argument in core constuctor
  /// @dev ^ that's needed for tvl accounting, once core is deployed this function is called
  /// @dev emits `SherlockCoreSet`
  function setSherlockCoreAddress(ISherlock _sherlock) external;

  /// @notice Pause external functions in contract
  function pause() external;

  /// @notice Unpause external functions in contract
  function unpause() external;
}

File 25 of 28 : ISherlockClaimManagerCallbackReceiver.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.10;

/******************************************************************************\
* Author: Evert Kors <[email protected]> (https://twitter.com/evert0x)
* Sherlock Protocol: https://sherlock.xyz
/******************************************************************************/

interface ISherlockClaimManagerCallbackReceiver {
  /// @notice Calls this function on approved contracts and passes args
  /// @param _protocol The protocol that is receiving the payout
  /// @param _claimID The claim ID that is receiving the payout
  /// @param _amount The amount of USDC being paid out for this claim
  function PreCorePayoutCallback(
    bytes32 _protocol,
    uint256 _claimID,
    uint256 _amount
  ) external;
}

File 26 of 28 : OptimisticRequester.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

import './SkinnyOptimisticOracleInterface.sol';

/**
 * @title Optimistic Requester.
 * @notice Optional interface that requesters can implement to receive callbacks.
 * @dev This contract does _not_ work with ERC777 collateral currencies or any others that call into the receiver on
 * transfer(). Using an ERC777 token would allow a user to maliciously grief other participants (while also losing
 * money themselves).
 */
interface OptimisticRequester {
  /**
   * @notice Callback for proposals.
   * @param identifier price identifier being requested.
   * @param timestamp timestamp of the price being requested.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request request params after proposal.
   */
  function priceProposed(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    SkinnyOptimisticOracleInterface.Request memory request
  ) external;

  /**
   * @notice Callback for disputes.
   * @param identifier price identifier being requested.
   * @param timestamp timestamp of the price being requested.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request request params after dispute.
   */
  function priceDisputed(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    SkinnyOptimisticOracleInterface.Request memory request
  ) external;

  /**
   * @notice Callback for settlement.
   * @param identifier price identifier being requested.
   * @param timestamp timestamp of the price being requested.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request request params after settlement.
   */
  function priceSettled(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    SkinnyOptimisticOracleInterface.Request memory request
  ) external;
}

File 27 of 28 : SkinnyOptimisticOracleInterface.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import './OptimisticOracleInterface.sol';

/**
 * @title Interface for the gas-cost-reduced version of the OptimisticOracle.
 * @notice Differences from normal OptimisticOracle:
 * - refundOnDispute: flag is removed, by default there are no refunds on disputes.
 * - customizing request parameters: In the OptimisticOracle, parameters like `bond` and `customLiveness` can be reset
 *   after a request is already made via `requestPrice`. In the SkinnyOptimisticOracle, these parameters can only be
 *   set in `requestPrice`, which has an expanded input set.
 * - settleAndGetPrice: Replaced by `settle`, which can only be called once per settleable request. The resolved price
 *   can be fetched via the `Settle` event or the return value of `settle`.
 * - general changes to interface: Functions that interact with existing requests all require the parameters of the
 *   request to modify to be passed as input. These parameters must match with the existing request parameters or the
 *   function will revert. This change reflects the internal refactor to store hashed request parameters instead of the
 *   full request struct.
 * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.
 */
abstract contract SkinnyOptimisticOracleInterface {
  event RequestPrice(
    address indexed requester,
    bytes32 indexed identifier,
    uint32 timestamp,
    bytes ancillaryData,
    Request request
  );
  event ProposePrice(
    address indexed requester,
    bytes32 indexed identifier,
    uint32 timestamp,
    bytes ancillaryData,
    Request request
  );
  event DisputePrice(
    address indexed requester,
    bytes32 indexed identifier,
    uint32 timestamp,
    bytes ancillaryData,
    Request request
  );
  event Settle(
    address indexed requester,
    bytes32 indexed identifier,
    uint32 timestamp,
    bytes ancillaryData,
    Request request
  );
  // Struct representing a price request. Note that this differs from the OptimisticOracleInterface's Request struct
  // in that refundOnDispute is removed.
  struct Request {
    address proposer; // Address of the proposer.
    address disputer; // Address of the disputer.
    IERC20 currency; // ERC20 token used to pay rewards and fees.
    bool settled; // True if the request is settled.
    int256 proposedPrice; // Price that the proposer submitted.
    int256 resolvedPrice; // Price resolved once the request is settled.
    uint256 expirationTime; // Time at which the request auto-settles without a dispute.
    uint256 reward; // Amount of the currency to pay to the proposer on settlement.
    uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.
    uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.
    uint256 customLiveness; // Custom liveness value set by the requester.
  }

  // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible
  // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses
  // to accept a price request made with ancillary data length over a certain size.
  uint256 public constant ancillaryBytesLimit = 8192;

  /**
   * @notice Requests a new price.
   * @param identifier price identifier being requested.
   * @param timestamp timestamp of the price being requested.
   * @param ancillaryData ancillary data representing additional args being passed with the price request.
   * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.
   * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,
   *               which could make sense if the contract requests and proposes the value in the same call or
   *               provides its own reward system.
   * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.
   * @param customLiveness custom proposal liveness to set for request.
   * @return totalBond default bond + final fee that the proposer and disputer will be required to pay.
   */
  function requestPrice(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    IERC20 currency,
    uint256 reward,
    uint256 bond,
    uint256 customLiveness
  ) external virtual returns (uint256 totalBond);

  /**
   * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come
   * from this proposal. However, any bonds are pulled from the caller.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request price request parameters whose hash must match the request that the caller wants to
   * propose a price for.
   * @param proposer address to set as the proposer.
   * @param proposedPrice price being proposed.
   * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
   * the proposer once settled if the proposal is correct.
   */
  function proposePriceFor(
    address requester,
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    Request memory request,
    address proposer,
    int256 proposedPrice
  ) public virtual returns (uint256 totalBond);

  /**
   * @notice Proposes a price value where caller is the proposer.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request price request parameters whose hash must match the request that the caller wants to
   * propose a price for.
   * @param proposedPrice price being proposed.
   * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
   * the proposer once settled if the proposal is correct.
   */
  function proposePrice(
    address requester,
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    Request memory request,
    int256 proposedPrice
  ) external virtual returns (uint256 totalBond);

  /**
   * @notice Combines logic of requestPrice and proposePrice while taking advantage of gas savings from not having to
   * overwrite Request params that a normal requestPrice() => proposePrice() flow would entail. Note: The proposer
   * will receive any rewards that come from this proposal. However, any bonds are pulled from the caller.
   * @dev The caller is the requester, but the proposer can be customized.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.
   * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,
   *               which could make sense if the contract requests and proposes the value in the same call or
   *               provides its own reward system.
   * @param bond custom proposal bond to set for request. If set to 0, defaults to the final fee.
   * @param customLiveness custom proposal liveness to set for request.
   * @param proposer address to set as the proposer.
   * @param proposedPrice price being proposed.
   * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
   * the proposer once settled if the proposal is correct.
   */
  function requestAndProposePriceFor(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    IERC20 currency,
    uint256 reward,
    uint256 bond,
    uint256 customLiveness,
    address proposer,
    int256 proposedPrice
  ) external virtual returns (uint256 totalBond);

  /**
   * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will
   * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request price request parameters whose hash must match the request that the caller wants to
   * dispute.
   * @param disputer address to set as the disputer.
   * @param requester sender of the initial price request.
   * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
   * the disputer once settled if the dispute was valid (the proposal was incorrect).
   */
  function disputePriceFor(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    Request memory request,
    address disputer,
    address requester
  ) public virtual returns (uint256 totalBond);

  /**
   * @notice Disputes a price request with an active proposal where caller is the disputer.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request price request parameters whose hash must match the request that the caller wants to
   * dispute.
   * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
   * the disputer once settled if the dispute was valid (the proposal was incorrect).
   */
  function disputePrice(
    address requester,
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    Request memory request
  ) external virtual returns (uint256 totalBond);

  /**
   * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request price request parameters whose hash must match the request that the caller wants to
   * settle.
   * @return payout the amount that the "winner" (proposer or disputer) receives on settlement. This amount includes
   * the returned bonds as well as additional rewards.
   * @return resolvedPrice the price that the request settled to.
   */
  function settle(
    address requester,
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    Request memory request
  ) external virtual returns (uint256 payout, int256 resolvedPrice);

  /**
   * @notice Computes the current state of a price request. See the State enum for more details.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request price request parameters.
   * @return the State.
   */
  function getState(
    address requester,
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    Request memory request
  ) external virtual returns (OptimisticOracleInterface.State);

  /**
   * @notice Checks if a given request has resolved, expired or been settled (i.e the optimistic oracle has a price).
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param request price request parameters. The hash of these parameters must match with the request hash that is
   * associated with the price request unique ID {requester, identifier, timestamp, ancillaryData}, or this method
   * will revert.
   * @return boolean indicating true if price exists and false if not.
   */
  function hasPrice(
    address requester,
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    Request memory request
  ) public virtual returns (bool);

  /**
   * @notice Generates stamped ancillary data in the format that it would be used in the case of a price dispute.
   * @param ancillaryData ancillary data of the price being requested.
   * @param requester sender of the initial price request.
   * @return the stamped ancillary bytes.
   */
  function stampAncillaryData(bytes memory ancillaryData, address requester)
    public
    pure
    virtual
    returns (bytes memory);
}

File 28 of 28 : OptimisticOracleInterface.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

/**
 * @title Financial contract facing Oracle interface.
 * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.
 */
abstract contract OptimisticOracleInterface {
  // Struct representing the state of a price request.
  enum State {
    Invalid, // Never requested.
    Requested, // Requested, no other actions taken.
    Proposed, // Proposed, but not expired or disputed yet.
    Expired, // Proposed, not disputed, past liveness.
    Disputed, // Disputed, but no DVM price returned yet.
    Resolved, // Disputed and DVM price is available.
    Settled // Final price has been set in the contract (can get here from Expired or Resolved).
  }

  // Struct representing a price request.
  struct Request {
    address proposer; // Address of the proposer.
    address disputer; // Address of the disputer.
    IERC20 currency; // ERC20 token used to pay rewards and fees.
    bool settled; // True if the request is settled.
    bool refundOnDispute; // True if the requester should be refunded their reward on dispute.
    int256 proposedPrice; // Price that the proposer submitted.
    int256 resolvedPrice; // Price resolved once the request is settled.
    uint256 expirationTime; // Time at which the request auto-settles without a dispute.
    uint256 reward; // Amount of the currency to pay to the proposer on settlement.
    uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.
    uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.
    uint256 customLiveness; // Custom liveness value set by the requester.
  }

  // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible
  // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses
  // to accept a price request made with ancillary data length over a certain size.
  uint256 public constant ancillaryBytesLimit = 8192;

  /**
   * @notice Requests a new price.
   * @param identifier price identifier being requested.
   * @param timestamp timestamp of the price being requested.
   * @param ancillaryData ancillary data representing additional args being passed with the price request.
   * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.
   * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,
   *               which could make sense if the contract requests and proposes the value in the same call or
   *               provides its own reward system.
   * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.
   * This can be changed with a subsequent call to setBond().
   */
  function requestPrice(
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData,
    IERC20 currency,
    uint256 reward
  ) external virtual returns (uint256 totalBond);

  /**
   * @notice Set the proposal bond associated with a price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param bond custom bond amount to set.
   * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be
   * changed again with a subsequent call to setBond().
   */
  function setBond(
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData,
    uint256 bond
  ) external virtual returns (uint256 totalBond);

  /**
   * @notice Sets the request to refund the reward if the proposal is disputed. This can help to "hedge" the caller
   * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's
   * bond, so there is still profit to be made even if the reward is refunded.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   */
  function setRefundOnDispute(
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData
  ) external virtual;

  /**
   * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before
   * being auto-resolved.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param customLiveness new custom liveness.
   */
  function setCustomLiveness(
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData,
    uint256 customLiveness
  ) external virtual;

  /**
   * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come
   * from this proposal. However, any bonds are pulled from the caller.
   * @param proposer address to set as the proposer.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param proposedPrice price being proposed.
   * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
   * the proposer once settled if the proposal is correct.
   */
  function proposePriceFor(
    address proposer,
    address requester,
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData,
    int256 proposedPrice
  ) public virtual returns (uint256 totalBond);

  /**
   * @notice Proposes a price value for an existing price request.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @param proposedPrice price being proposed.
   * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to
   * the proposer once settled if the proposal is correct.
   */
  function proposePrice(
    address requester,
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData,
    int256 proposedPrice
  ) external virtual returns (uint256 totalBond);

  /**
   * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will
   * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.
   * @param disputer address to set as the disputer.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to
   * the disputer once settled if the dispute was value (the proposal was incorrect).
   */
  function disputePriceFor(
    address disputer,
    address requester,
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData
  ) public virtual returns (uint256 totalBond);

  /**
   * @notice Disputes a price value for an existing price request with an active proposal.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to
   * the disputer once settled if the dispute was valid (the proposal was incorrect).
   */
  function disputePrice(
    address requester,
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData
  ) external virtual returns (uint256 totalBond);

  /**
   * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled
   * or settleable. Note: this method is not view so that this call may actually settle the price request if it
   * hasn't been settled.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @return resolved price.
   */
  function settleAndGetPrice(
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData
  ) external virtual returns (int256);

  /**
   * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @return payout the amount that the "winner" (proposer or disputer) receives on settlement. This amount includes
   * the returned bonds as well as additional rewards.
   */
  function settle(
    address requester,
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData
  ) external virtual returns (uint256 payout);

  /**
   * @notice Gets the current data structure containing all information about a price request.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @return the Request data structure.
   */
  function getRequest(
    address requester,
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData
  ) public view virtual returns (Request memory);

  /**
   * @notice Returns the state of a price request.
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @return the State enum value.
   */
  function getState(
    address requester,
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData
  ) public view virtual returns (State);

  /**
   * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).
   * @param requester sender of the initial price request.
   * @param identifier price identifier to identify the existing request.
   * @param timestamp timestamp to identify the existing request.
   * @param ancillaryData ancillary data of the price being requested.
   * @return true if price has resolved or settled, false otherwise.
   */
  function hasPrice(
    address requester,
    bytes32 identifier,
    uint256 timestamp,
    bytes memory ancillaryData
  ) public view virtual returns (bool);

  function stampAncillaryData(bytes memory ancillaryData, address requester)
    public
    view
    virtual
    returns (bytes memory);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"contract IERC20","name":"_sher","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"contract IStrategyManager","name":"_yieldStrategy","type":"address"},{"internalType":"contract ISherDistributionManager","name":"_sherDistributionManager","type":"address"},{"internalType":"address","name":"_nonStakersAddress","type":"address"},{"internalType":"contract ISherlockProtocolManager","name":"_sherlockProtocolManager","type":"address"},{"internalType":"contract ISherlockClaimManager","name":"_sherlockClaimManager","type":"address"},{"internalType":"uint256[]","name":"_initialstakingPeriods","type":"uint256[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidArgument","type":"error"},{"inputs":[],"name":"InvalidConditions","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InvalidSherAmount","type":"error"},{"inputs":[],"name":"NonExistent","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroArgument","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"ArbRestaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISherlockClaimManager","name":"previous","type":"address"},{"indexed":false,"internalType":"contract ISherlockClaimManager","name":"current","type":"address"}],"name":"ClaimManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimPayout","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previous","type":"address"},{"indexed":false,"internalType":"address","name":"current","type":"address"}],"name":"NonStakerAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISherlockProtocolManager","name":"previous","type":"address"},{"indexed":false,"internalType":"contract ISherlockProtocolManager","name":"current","type":"address"}],"name":"ProtocolManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"Restaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISherDistributionManager","name":"previous","type":"address"},{"indexed":false,"internalType":"contract ISherDistributionManager","name":"current","type":"address"}],"name":"SherDistributionManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"period","type":"uint256"}],"name":"StakingPeriodDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"period","type":"uint256"}],"name":"StakingPeriodEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"error","type":"bytes"}],"name":"YieldStrategyUpdateWithdrawAllError","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IStrategyManager","name":"previous","type":"address"},{"indexed":false,"internalType":"contract IStrategyManager","name":"current","type":"address"}],"name":"YieldStrategyUpdated","type":"event"},{"inputs":[],"name":"ARB_RESTAKE_GROWTH_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ARB_RESTAKE_MAX_PERCENTAGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ARB_RESTAKE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ARB_RESTAKE_WAIT_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STAKE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"arbRestake","outputs":[{"internalType":"uint256","name":"_sher","type":"uint256"},{"internalType":"uint256","name":"_arbReward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"disableStakingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"enableStakingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"initialStake","outputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_sher","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenID","type":"uint256"}],"name":"lockupEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonStakersAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"}],"name":"ownerRestake","outputs":[{"internalType":"uint256","name":"_sher","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"payoutClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"redeemNFT","outputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeSherDistributionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sher","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sherDistributionManager","outputs":[{"internalType":"contract ISherDistributionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenID","type":"uint256"}],"name":"sherRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sherlockClaimManager","outputs":[{"internalType":"contract ISherlockClaimManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sherlockProtocolManager","outputs":[{"internalType":"contract ISherlockProtocolManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakingPeriods","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenID","type":"uint256"}],"name":"tokenBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokenBalanceStakers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nonStakers","type":"address"}],"name":"updateNonStakersAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISherDistributionManager","name":"_sherDistributionManager","type":"address"}],"name":"updateSherDistributionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISherlockClaimManager","name":"_claimManager","type":"address"}],"name":"updateSherlockClaimManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISherlockProtocolManager","name":"_protocolManager","type":"address"}],"name":"updateSherlockProtocolManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStrategyManager","name":"_yieldStrategy","type":"address"}],"name":"updateYieldStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStrategyManager","name":"_yieldStrategy","type":"address"}],"name":"updateYieldStrategyForce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"viewRewardForArbRestake","outputs":[{"internalType":"uint256","name":"profit","type":"uint256"},{"internalType":"bool","name":"able","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yieldStrategy","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"yieldStrategyDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"yieldStrategyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"yieldStrategyWithdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c06040523480156200001157600080fd5b506040516200585338038062005853833981016040819052620000349162000733565b8751889088906200004d9060009060208501906200050a565b508051620000639060019060208401906200050a565b505050620000806200007a620003ae60201b60201c565b620003b2565b6006805460ff60a01b191690556001600160a01b038a16620000b55760405163b7852ebb60e01b815260040160405180910390fd5b6001600160a01b038916620000dd5760405163b7852ebb60e01b815260040160405180910390fd5b6001600160a01b038616620001055760405163b7852ebb60e01b815260040160405180910390fd5b6001600160a01b0385166200012d5760405163b7852ebb60e01b815260040160405180910390fd5b6001600160a01b038416620001555760405163b7852ebb60e01b815260040160405180910390fd5b6001600160a01b0383166200017d5760405163b7852ebb60e01b815260040160405180910390fd5b6001600160a01b038216620001a55760405163b7852ebb60e01b815260040160405180910390fd5b6001600160a01b038a811660805289811660a052600c80546001600160a01b031990811689841617909155600d80548216888416179055601080548216878416179055600e80548216868416179055600f805490911691841691909117905560005b815181101562000253576200023e8282815181106200022a576200022a6200084a565b60200260200101516200040460201b60201c565b806200024a8162000860565b91505062000207565b5060408051600081526001600160a01b03881660208201527fbffd2f20a06ca0304329080309bdd314339b2a5afe9927f8b3100220b661c947910160405180910390a160408051600081526001600160a01b03871660208201527f24062d083f038a9c1aeff4eaa632dd2d026ce766bb41fa307198b6ab6cd003f7910160405180910390a160408051600081526001600160a01b03861660208201527f858040f45f3b8fa15a490ee8748c18344557eee85411d16032375a72ede42131910160405180910390a160408051600081526001600160a01b03851660208201527f73f2888686ab9a383b3e15e1af51c0bf844f02338c8d0b4b4e3f266a99c1e6ac910160405180910390a160408051600081526001600160a01b03841660208201527f4fb8c694740ad02d97e96c5bdd165d6e51d1a11e569be600ac432012b41ccf75910160405180910390a150505050505050505050620008c7565b3390565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6006546001600160a01b03163314620004635760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640160405180910390fd5b80620004825760405163b7852ebb60e01b815260040160405180910390fd5b60008181526007602052604090205460ff1615620004b35760405163a9cb9e0d60e01b815260040160405180910390fd5b60008181526007602052604090819020805460ff19166001179055517f3cc8bc2ec3ed67adce54f8d51791fff47b8bd6b911e75d2d5fefbde81e971d5c90620004ff9083815260200190565b60405180910390a150565b82805462000518906200088a565b90600052602060002090601f0160209004810192826200053c576000855562000587565b82601f106200055757805160ff191683800117855562000587565b8280016001018555821562000587579182015b82811115620005875782518255916020019190600101906200056a565b506200059592915062000599565b5090565b5b808211156200059557600081556001016200059a565b80516001600160a01b0381168114620005c857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200060e576200060e620005cd565b604052919050565b600082601f8301126200062857600080fd5b81516001600160401b03811115620006445762000644620005cd565b60206200065a601f8301601f19168201620005e3565b82815285828487010111156200066f57600080fd5b60005b838110156200068f57858101830151828201840152820162000672565b83811115620006a15760008385840101525b5095945050505050565b600082601f830112620006bd57600080fd5b815160206001600160401b03821115620006db57620006db620005cd565b8160051b620006ec828201620005e3565b92835284810182019282810190878511156200070757600080fd5b83870192505b8483101562000728578251825291830191908301906200070d565b979650505050505050565b6000806000806000806000806000806101408b8d0312156200075457600080fd5b6200075f8b620005b0565b99506200076f60208c01620005b0565b60408c01519099506001600160401b03808211156200078d57600080fd5b6200079b8e838f0162000616565b995060608d0151915080821115620007b257600080fd5b620007c08e838f0162000616565b9850620007d060808e01620005b0565b9750620007e060a08e01620005b0565b9650620007f060c08e01620005b0565b95506200080060e08e01620005b0565b9450620008116101008e01620005b0565b93506101208d01519150808211156200082957600080fd5b50620008388d828e01620006ab565b9150509295989b9194979a5092959850565b634e487b7160e01b600052603260045260246000fd5b60006000198214156200088357634e487b7160e01b600052601160045260246000fd5b5060010190565b600181811c908216806200089f57607f821691505b60208210811415620008c157634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a051614f2e6200092560003960008181610624015281816137ab015281816138fc0152613c190152600081816107aa01528181610e07015281816111fc01528181612a2c01528181613cd80152613dcf0152614f2e6000f3fe608060405234801561001057600080fd5b50600436106103625760003560e01c806375692116116101c8578063aaf5ced611610104578063c87b56dd116100a2578063e68b77571161007c578063e68b775714610743578063e985e9c514610756578063f2fde38b14610792578063fc0c546a146107a557600080fd5b8063c87b56dd14610717578063cb1c2b5c1461072a578063e4b89ee91461073457600080fd5b8063b88d4fde116100de578063b88d4fde146106d4578063bb3f3724146106e7578063bf362cb9146106fa578063bfbb8a8d1461070d57600080fd5b8063aaf5ced6146106a4578063abb81298146106ae578063ac96058f146106c157600080fd5b8063937840b01161017157806396a7392d1161014b57806396a7392d14610658578063975a8b021461066b57806398ec930f1461067e578063a22cb4651461069157600080fd5b8063937840b01461061f578063939dcc7e1461064657806395d89b411461065057600080fd5b80638af92c93116101a25780638af92c93146105d85780638da5cb5b146105fb5780639047acef1461060c57600080fd5b806375692116146105b55780638456cb59146105bd578063863a43d5146105c557600080fd5b80633f4ba83a116102a25780635eb926a9116102405780636422c6291161021a5780636422c629146105745780636733643f1461058757806370a082311461059a578063715018a6146105ad57600080fd5b80635eb926a91461053b578063624090111461054e5780636352211e1461056157600080fd5b806356e24d371161027c57806356e24d37146104df57806358dc2cdb146104f25780635c975abb146105055780635ea09ae71461052857600080fd5b80633f4ba83a146104b157806342842e0e146104b957806354972fc3146104cc57600080fd5b806313f14fee1161030f5780631a9b9c77116102e95780631a9b9c771461045b57806323b872dd1461046e5780632f5cf62b1461048157806330179ceb146104a957600080fd5b806313f14fee1461042d57806313f4dd25146104405780631878fbf31461045357600080fd5b8063081812fc11610340578063081812fc146103cc578063095ea7b3146103f757806310099abf1461040c57600080fd5b806301ffc9a71461036757806306fdde031461038f57806307441979146103a4575b600080fd5b61037a6103753660046148f0565b6107cc565b60405190151581526020015b60405180910390f35b6103976108b1565b6040516103869190614983565b6103b76103b2366004614996565b610943565b60408051928352901515602083015201610386565b6103df6103da366004614996565b6109b1565b6040516001600160a01b039091168152602001610386565b61040a6104053660046149c4565b610a5c565b005b61041f61041a3660046149f0565b610b8e565b604051908152602001610386565b600c546103df906001600160a01b031681565b61041f61044e366004614996565b610c5f565b61041f610cdb565b61040a610469366004614996565b610e93565b61040a61047c366004614a12565b610fe1565b61049461048f366004614a53565b611068565b60408051928352602083019190915201610386565b61040a6112ad565b61040a611383565b61040a6104c7366004614a12565b611790565b61040a6104da366004614a8c565b6117ab565b61040a6104ed366004614a8c565b61190e565b61041f610500366004614996565b611a71565b60065474010000000000000000000000000000000000000000900460ff1661037a565b61040a610536366004614a8c565b611b2d565b61040a610549366004614a8c565b611c90565b61040a61055c3660046149c4565b611ef5565b6103df61056f366004614996565b611ffa565b61041f610582366004614996565b612085565b61040a610595366004614996565b6120e6565b61041f6105a8366004614a8c565b6121f1565b61040a61228b565b61040a6122ef565b61040a6123fb565b600e546103df906001600160a01b031681565b61037a6105e6366004614996565b60076020526000908152604090205460ff1681565b6006546001600160a01b03166103df565b61049461061a366004614996565b6127ec565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b61041f62eff10081565b610397612914565b6010546103df906001600160a01b031681565b600f546103df906001600160a01b031681565b61040a61068c366004614996565b612923565b61040a61069f366004614ab7565b612aa6565b61041f62093a8081565b600d546103df906001600160a01b031681565b61040a6106cf366004614996565b612ab5565b61040a6106e2366004614b1f565b612bbd565b61040a6106f5366004614a8c565b612c45565b61041f610708366004614996565b612da8565b61041f6212750081565b610397610725366004614996565b612e09565b61041f620f424081565b61041f6702c68af0bb14000081565b61040a610751366004614a8c565b612ef1565b61037a610764366004614c1d565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61040a6107a0366004614a8c565b61304c565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061085f57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b806108ab57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6060600080546108c090614c4b565b80601f01602080910402602001604051908101604052809291908181526020018280546108ec90614c4b565b80156109395780601f1061090e57610100808354040283529160200191610939565b820191906000526020600020905b81548152906001019060200180831161091c57829003601f168201915b5050505050905090565b60008181526002602052604081205481906001600160a01b0316610993576040517f2f9d01c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61099c8361312b565b90925090506109aa826131ef565b9150915091565b6000818152600260205260408120546001600160a01b0316610a405760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e000000000000000000000000000000000000000060648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b6000610a6782611ffa565b9050806001600160a01b0316836001600160a01b03161415610af15760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610a37565b336001600160a01b0382161480610b0d5750610b0d8133610764565b610b7f5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610a37565b610b898383613206565b505050565b60065460009074010000000000000000000000000000000000000000900460ff1615610bfc5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b610c058361328c565b60008281526007602052604090205460ff16610c4d576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c5883833361331e565b9392505050565b6000818152600260205260408120546001600160a01b0316610cad576040517f2f9d01c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b54610cb8610cdb565b6000848152600a6020526040902054610cd19190614cce565b6108ab9190614d3a565b600e54604080517f9703879c00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691639703879c9160048083019260209291908290030181865afa158015610d3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d629190614d4e565b600c60009054906101000a90046001600160a01b03166001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd99190614d4e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610e56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7a9190614d4e565b610e849190614d67565b610e8e9190614d67565b905090565b6006546001600160a01b03163314610eed5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b80610f24576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604090205460ff1615610f6d576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f3cc8bc2ec3ed67adce54f8d51791fff47b8bd6b911e75d2d5fefbde81e971d5c90610fd69083815260200190565b60405180910390a150565b610feb3382613373565b61105d5760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610a37565b610b8983838361347b565b60008061109060065460ff740100000000000000000000000000000000000000009091041690565b156110dd5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b84611114576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620f4240851015611151576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526007602052604090205460ff16611199576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383166111d9576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011600081546111e890614d7f565b918290555091506112246001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308861366b565b600b54600090801561125e5786611239610cdb565b6112439190614db8565b61124d8289614cce565b6112579190614d3a565b9150611262565b8691505b6000848152600a60205260408120839055600b8054849290611285908490614d67565b9091555061129790508787868861373a565b92506112a385856139d8565b5050935093915050565b6006546001600160a01b031633146113075760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b600c60009054906101000a90046001600160a01b03166001600160a01b031663853828b66040518163ffffffff1660e01b81526004016020604051808303816000875af115801561135c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113809190614d4e565b50565b6006546001600160a01b031633146113dd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6113e56139f2565b600c60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611438573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145c9190614dcf565b156114ca57600c60009054906101000a90046001600160a01b03166001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156114b157600080fd5b505af11580156114c5573d6000803e3d6000fd5b505050505b600d546001600160a01b0316158015906115565750600d60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611532573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115569190614dcf565b156115c457600d60009054906101000a90046001600160a01b03166001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156115ab57600080fd5b505af11580156115bf573d6000803e3d6000fd5b505050505b600e60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611617573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163b9190614dcf565b156116a957600e60009054906101000a90046001600160a01b03166001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561169057600080fd5b505af11580156116a4573d6000803e3d6000fd5b505050505b600f60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117209190614dcf565b1561178e57600f60009054906101000a90046001600160a01b03166001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561177557600080fd5b505af1158015611789573d6000803e3d6000fd5b505050505b565b610b8983838360405180602001604052806000815250612bbd565b6006546001600160a01b031633146118055760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116611845576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6010546001600160a01b038281169116141561188d576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601054604080516001600160a01b03928316815291831660208301527f858040f45f3b8fa15a490ee8748c18344557eee85411d16032375a72ede42131910160405180910390a1601080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6006546001600160a01b031633146119685760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b0381166119a8576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d546001600160a01b03828116911614156119f0576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d54604080516001600160a01b03928316815291831660208301527f24062d083f038a9c1aeff4eaa632dd2d026ce766bb41fa307198b6ab6cd003f7910160405180910390a1600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60065460009074010000000000000000000000000000000000000000900460ff1615611adf5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b611ae88261328c565b611af182613ac4565b6000828152600a6020526040902054611b0c90839033613b83565b9050611b188233613be4565b60009182526008602052604082209190915590565b6006546001600160a01b03163314611b875760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116611bc7576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546001600160a01b0382811691161415611c0f576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e54604080516001600160a01b03928316815291831660208301527f73f2888686ab9a383b3e15e1af51c0bf844f02338c8d0b4b4e3f266a99c1e6ac910160405180910390a1600e80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6006546001600160a01b03163314611cea5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116611d2a576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c546001600160a01b0382811691161415611d72576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c60009054906101000a90046001600160a01b03166001600160a01b031663853828b66040518163ffffffff1660e01b81526004016020604051808303816000875af1925050508015611e01575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611dfe91810190614d4e565b60015b611e72573d808015611e2f576040519150601f19603f3d011682016040523d82523d6000602084013e611e34565b606091505b507ffe257ff0b8b9234a845b6da819fdd8bb73b1d3baf5ec0bfca0afdf884aaef54381604051611e649190614983565b60405180910390a150611e74565b505b600c54604080516001600160a01b03928316815291831660208301527fbffd2f20a06ca0304329080309bdd314339b2a5afe9927f8b3100220b661c947910160405180910390a1600c80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60065474010000000000000000000000000000000000000000900460ff1615611f605760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b600f546001600160a01b03163314611fa4576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015611fb457611fb48282613c40565b604080516001600160a01b0384168152602081018390527f86d1859fdb12afcb2875bb01d9996ad35d9dd55f62a87e76d9853161111b19ce910160405180910390a15050565b6000818152600260205260408120546001600160a01b0316806108ab5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201527f656e7420746f6b656e00000000000000000000000000000000000000000000006064820152608401610a37565b6000818152600260205260408120546001600160a01b03166120d3576040517f2f9d01c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009081526009602052604090205490565b6006546001600160a01b031633146121405760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b80612177576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c546040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b1580156121d657600080fd5b505af11580156121ea573d6000803e3d6000fd5b5050505050565b60006001600160a01b03821661226f5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610a37565b506001600160a01b031660009081526003602052604090205490565b6006546001600160a01b031633146122e55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b61178e6000613df6565b6006546001600160a01b031633146123495760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b600d546001600160a01b031661238b576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d54604080516001600160a01b039092168252600060208301527f24062d083f038a9c1aeff4eaa632dd2d026ce766bb41fa307198b6ab6cd003f7910160405180910390a1600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6006546001600160a01b031633146124555760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b61245d613e60565b600c60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d49190614dcf565b61254157600c60009054906101000a90046001600160a01b03166001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561252857600080fd5b505af115801561253c573d6000803e3d6000fd5b505050505b600d546001600160a01b0316158015906125cf5750600d60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125cd9190614dcf565b155b1561263d57600d60009054906101000a90046001600160a01b03166001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561262457600080fd5b505af1158015612638573d6000803e3d6000fd5b505050505b600e60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612690573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b49190614dcf565b61272157600e60009054906101000a90046001600160a01b03166001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561270857600080fd5b505af115801561271c573d6000803e3d6000fd5b505050505b600f60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612774573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127989190614dcf565b61178e57600f60009054906101000a90046001600160a01b03166001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561177557600080fd5b60008061281460065460ff740100000000000000000000000000000000000000009091041690565b156128615760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b600061286c84611ffa565b905060008061287a8661312b565b91509150806128b5576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128c0868333613b83565b93506128d08662eff1008561331e565b9450857f55cf5b0b0c4865ff48ccec25327df9c608efaf77250f54b9dbb4a3833100fb4d8560405161290491815260200190565b60405180910390a2505050915091565b6060600180546108c090614c4b565b6006546001600160a01b0316331461297d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b806129b4576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e60009054906101000a90046001600160a01b03166001600160a01b031663ce104f086040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a0457600080fd5b505af1158015612a18573d6000803e3d6000fd5b5050600c54612a5692506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811692501683613f32565b600c60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db06040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156121d657600080fd5b612ab1338383613f7b565b5050565b6006546001600160a01b03163314612b0f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b60008181526007602052604090205460ff16612b57576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517fa12571933ed68ec934e0a44f7702f6a8c284f907672c05b6eb02a6a1541a83a290610fd69083815260200190565b612bc73383613373565b612c395760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610a37565b61178984848484614068565b6006546001600160a01b03163314612c9f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116612cdf576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f546001600160a01b0382811691161415612d27576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f54604080516001600160a01b03928316815291831660208301527f4fb8c694740ad02d97e96c5bdd165d6e51d1a11e569be600ac432012b41ccf75910160405180910390a1600f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000818152600260205260408120546001600160a01b0316612df6576040517f2f9d01c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009081526008602052604090205490565b6000818152600260205260409020546060906001600160a01b0316612e965760405162461bcd60e51b815260206004820152602f60248201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60448201527f6e6578697374656e7420746f6b656e00000000000000000000000000000000006064820152608401610a37565b6000612ea06140f1565b90506000815111612ec05760405180602001604052806000815250610c58565b80612eca84614111565b604051602001612edb929190614dec565b6040516020818303038152906040529392505050565b6006546001600160a01b03163314612f4b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116612f8b576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c546001600160a01b0382811691161415612fd3576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c60009054906101000a90046001600160a01b03166001600160a01b031663853828b66040518163ffffffff1660e01b81526004016020604051808303816000875af1158015613028573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e729190614d4e565b6006546001600160a01b031633146130a65760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b0381166131225760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a37565b61138081613df6565b6000818152600860205260408120548190819061314c906212750090614d67565b9050428111156131625750600093849350915050565b600061317162093a8083614d67565b905060008142106131825781613184565b425b6000878152600a6020526040812054919250906131a9906702c68af0bb140000614cce565b9050670de0b6b3a764000062093a80826131c38786614db8565b6131cd9190614cce565b6131d79190614d3a565b6131e19190614d3a565b976001975095505050505050565b6000600b546131fc610cdb565b610cd19084614cce565b600081815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038416908117909155819061325382611ffa565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b3361329682611ffa565b6001600160a01b0316146132d6576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260086020526040902054421015611380576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061332a8483613be4565b61333e61333685610c5f565b84868561373a565b60405190915084907fd56ee5c2e47aa11e45be71e49c4d945f32b196e4d5689412bf45bb6ae6253d0190600090a29392505050565b6000818152600260205260408120546001600160a01b03166133fd5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e00000000000000000000000000000000000000006064820152608401610a37565b600061340883611ffa565b9050806001600160a01b0316846001600160a01b031614806134435750836001600160a01b0316613438846109b1565b6001600160a01b0316145b8061347357506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b826001600160a01b031661348e82611ffa565b6001600160a01b03161461350a5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201527f73206e6f74206f776e00000000000000000000000000000000000000000000006064820152608401610a37565b6001600160a01b0382166135855760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610a37565b613590838383614243565b61359b600082613206565b6001600160a01b03831660009081526003602052604081208054600192906135c4908490614db8565b90915550506001600160a01b03821660009081526003602052604081208054600192906135f2908490614d67565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6040516001600160a01b03808516602483015283166044820152606481018290526117899085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526142ae565b60006137468442614d67565b600084815260086020526040902055600d546001600160a01b031661376d57506000613473565b8461377a57506000613473565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156137fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061381e9190614d4e565b600d546040517fd353b94c0000000000000000000000000000000000000000000000000000000081526004810189905260248101889052604481018790526001600160a01b03868116606483015292935091169063d353b94c906084016020604051808303816000875af115801561389a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138be9190614d4e565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290925060009082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015613943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139679190614d4e565b6139719190614db8565b90508281146139b6576040517f0c61d1f60000000000000000000000000000000000000000000000000000000081526004810184905260248101829052604401610a37565b82156139ce5760008581526009602052604090208390555b5050949350505050565b612ab1828260405180602001604052806000815250614393565b60065474010000000000000000000000000000000000000000900460ff16613a5c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a37565b600680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000613acf82611ffa565b9050613add81600084614243565b613ae8600083613206565b6001600160a01b0381166000908152600360205260408120805460019290613b11908490614db8565b909155505060008281526002602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000613b8e836131ef565b90508015613ba057613ba08282613c40565b6000848152600a602052604081208054859290613bbe908490614db8565b9250508190555082600b6000828254613bd79190614db8565b9091555090949350505050565b60008281526009602052604090205480613bfd57505050565b600083815260096020526040812055610b896001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383613f32565b600e60009054906101000a90046001600160a01b03166001600160a01b031663ce104f086040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613c9057600080fd5b505af1158015613ca4573d6000803e3d6000fd5b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691506370a0823190602401602060405180830381865afa158015613d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d4c9190614d4e565b905080821115613dc257600c546001600160a01b0316632e1a7d4d613d718385614db8565b6040518263ffffffff1660e01b8152600401613d8f91815260200190565b600060405180830381600087803b158015613da957600080fd5b505af1158015613dbd573d6000803e3d6000fd5b505050505b610b896001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168484613f32565b600680546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60065474010000000000000000000000000000000000000000900460ff1615613ecb5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b600680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613aa73390565b6040516001600160a01b038316602482015260448101829052610b899084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016136b8565b816001600160a01b0316836001600160a01b03161415613fdd5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610a37565b6001600160a01b0383811660008181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61407384848461347b565b61407f8484848461441c565b6117895760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610a37565b6060604051806060016040528060258152602001614ed460259139905090565b60608161415157505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561417b578061416581614d7f565b91506141749050600a83614d3a565b9150614155565b60008167ffffffffffffffff81111561419657614196614af0565b6040519080825280601f01601f1916602001820160405280156141c0576020820181803683370190505b5090505b8415613473576141d5600183614db8565b91506141e2600a86614e1b565b6141ed906030614d67565b60f81b81838151811061420257614202614e2f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061423c600a86614d3a565b94506141c4565b60065474010000000000000000000000000000000000000000900460ff1615610b895760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b6000614303826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145d59092919063ffffffff16565b805190915015610b8957808060200190518101906143219190614dcf565b610b895760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a37565b61439d83836145e4565b6143aa600084848461441c565b610b895760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610a37565b60006001600160a01b0384163b156145cd576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063150b7a0290614479903390899088908890600401614e5e565b6020604051808303816000875af19250505080156144d2575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526144cf91810190614e9a565b60015b614582573d808015614500576040519150601f19603f3d011682016040523d82523d6000602084013e614505565b606091505b50805161457a5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610a37565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149050613473565b506001613473565b6060613473848460008561474a565b6001600160a01b03821661463a5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610a37565b6000818152600260205260409020546001600160a01b03161561469f5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610a37565b6146ab60008383614243565b6001600160a01b03821660009081526003602052604081208054600192906146d4908490614d67565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6060824710156147c25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a37565b843b6148105760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a37565b600080866001600160a01b0316858760405161482c9190614eb7565b60006040518083038185875af1925050503d8060008114614869576040519150601f19603f3d011682016040523d82523d6000602084013e61486e565b606091505b509150915061487e828286614889565b979650505050505050565b60608315614898575081610c58565b8251156148a85782518084602001fd5b8160405162461bcd60e51b8152600401610a379190614983565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461138057600080fd5b60006020828403121561490257600080fd5b8135610c58816148c2565b60005b83811015614928578181015183820152602001614910565b838111156117895750506000910152565b6000815180845261495181602086016020860161490d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c586020830184614939565b6000602082840312156149a857600080fd5b5035919050565b6001600160a01b038116811461138057600080fd5b600080604083850312156149d757600080fd5b82356149e2816149af565b946020939093013593505050565b60008060408385031215614a0357600080fd5b50508035926020909101359150565b600080600060608486031215614a2757600080fd5b8335614a32816149af565b92506020840135614a42816149af565b929592945050506040919091013590565b600080600060608486031215614a6857600080fd5b83359250602084013591506040840135614a81816149af565b809150509250925092565b600060208284031215614a9e57600080fd5b8135610c58816149af565b801515811461138057600080fd5b60008060408385031215614aca57600080fd5b8235614ad5816149af565b91506020830135614ae581614aa9565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060008060808587031215614b3557600080fd5b8435614b40816149af565b93506020850135614b50816149af565b925060408501359150606085013567ffffffffffffffff80821115614b7457600080fd5b818701915087601f830112614b8857600080fd5b813581811115614b9a57614b9a614af0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715614be057614be0614af0565b816040528281528a6020848701011115614bf957600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215614c3057600080fd5b8235614c3b816149af565b91506020830135614ae5816149af565b600181811c90821680614c5f57607f821691505b60208210811415614c99577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614d0657614d06614c9f565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614d4957614d49614d0b565b500490565b600060208284031215614d6057600080fd5b5051919050565b60008219821115614d7a57614d7a614c9f565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614db157614db1614c9f565b5060010190565b600082821015614dca57614dca614c9f565b500390565b600060208284031215614de157600080fd5b8151610c5881614aa9565b60008351614dfe81846020880161490d565b835190830190614e1281836020880161490d565b01949350505050565b600082614e2a57614e2a614d0b565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006001600160a01b03808716835280861660208401525083604083015260806060830152614e906080830184614939565b9695505050505050565b600060208284031215614eac57600080fd5b8151610c58816148c2565b60008251614ec981846020870161490d565b919091019291505056fe68747470733a2f2f6e66742e736865726c6f636b2e78797a2f6170692f6d61696e6e65742fa26469706673582212200e87f14c7fb0f108d25dd551de75d1569a694919aeacae263b7f059ed8fe374264736f6c634300080a0033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000046d2a90153cd8f09464ca3a5605b6bbec9c2ff0100000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000f02d3a6288d998b412ce749cff244c8ef799f5820000000000000000000000005775f32787656e77dd99f20f4e478ddc85fdb31b000000000000000000000000666b8ebfbf4d5f0ce56962a25635cff563f131610000000000000000000000003d0b8a0a10835ab9b0f0beb54c5400b8aacaa1d3000000000000000000000000feedd254ae4b7c44a0472bb836b813ce4625eb8400000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000020536865726c6f636b205374616b696e6720506f736974696f6e204e46542d56310000000000000000000000000000000000000000000000000000000000000008534845522d504f5300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000eff1000000000000000000000000000000000000000000000000000000000001dfe200

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103625760003560e01c806375692116116101c8578063aaf5ced611610104578063c87b56dd116100a2578063e68b77571161007c578063e68b775714610743578063e985e9c514610756578063f2fde38b14610792578063fc0c546a146107a557600080fd5b8063c87b56dd14610717578063cb1c2b5c1461072a578063e4b89ee91461073457600080fd5b8063b88d4fde116100de578063b88d4fde146106d4578063bb3f3724146106e7578063bf362cb9146106fa578063bfbb8a8d1461070d57600080fd5b8063aaf5ced6146106a4578063abb81298146106ae578063ac96058f146106c157600080fd5b8063937840b01161017157806396a7392d1161014b57806396a7392d14610658578063975a8b021461066b57806398ec930f1461067e578063a22cb4651461069157600080fd5b8063937840b01461061f578063939dcc7e1461064657806395d89b411461065057600080fd5b80638af92c93116101a25780638af92c93146105d85780638da5cb5b146105fb5780639047acef1461060c57600080fd5b806375692116146105b55780638456cb59146105bd578063863a43d5146105c557600080fd5b80633f4ba83a116102a25780635eb926a9116102405780636422c6291161021a5780636422c629146105745780636733643f1461058757806370a082311461059a578063715018a6146105ad57600080fd5b80635eb926a91461053b578063624090111461054e5780636352211e1461056157600080fd5b806356e24d371161027c57806356e24d37146104df57806358dc2cdb146104f25780635c975abb146105055780635ea09ae71461052857600080fd5b80633f4ba83a146104b157806342842e0e146104b957806354972fc3146104cc57600080fd5b806313f14fee1161030f5780631a9b9c77116102e95780631a9b9c771461045b57806323b872dd1461046e5780632f5cf62b1461048157806330179ceb146104a957600080fd5b806313f14fee1461042d57806313f4dd25146104405780631878fbf31461045357600080fd5b8063081812fc11610340578063081812fc146103cc578063095ea7b3146103f757806310099abf1461040c57600080fd5b806301ffc9a71461036757806306fdde031461038f57806307441979146103a4575b600080fd5b61037a6103753660046148f0565b6107cc565b60405190151581526020015b60405180910390f35b6103976108b1565b6040516103869190614983565b6103b76103b2366004614996565b610943565b60408051928352901515602083015201610386565b6103df6103da366004614996565b6109b1565b6040516001600160a01b039091168152602001610386565b61040a6104053660046149c4565b610a5c565b005b61041f61041a3660046149f0565b610b8e565b604051908152602001610386565b600c546103df906001600160a01b031681565b61041f61044e366004614996565b610c5f565b61041f610cdb565b61040a610469366004614996565b610e93565b61040a61047c366004614a12565b610fe1565b61049461048f366004614a53565b611068565b60408051928352602083019190915201610386565b61040a6112ad565b61040a611383565b61040a6104c7366004614a12565b611790565b61040a6104da366004614a8c565b6117ab565b61040a6104ed366004614a8c565b61190e565b61041f610500366004614996565b611a71565b60065474010000000000000000000000000000000000000000900460ff1661037a565b61040a610536366004614a8c565b611b2d565b61040a610549366004614a8c565b611c90565b61040a61055c3660046149c4565b611ef5565b6103df61056f366004614996565b611ffa565b61041f610582366004614996565b612085565b61040a610595366004614996565b6120e6565b61041f6105a8366004614a8c565b6121f1565b61040a61228b565b61040a6122ef565b61040a6123fb565b600e546103df906001600160a01b031681565b61037a6105e6366004614996565b60076020526000908152604090205460ff1681565b6006546001600160a01b03166103df565b61049461061a366004614996565b6127ec565b6103df7f00000000000000000000000046d2a90153cd8f09464ca3a5605b6bbec9c2ff0181565b61041f62eff10081565b610397612914565b6010546103df906001600160a01b031681565b600f546103df906001600160a01b031681565b61040a61068c366004614996565b612923565b61040a61069f366004614ab7565b612aa6565b61041f62093a8081565b600d546103df906001600160a01b031681565b61040a6106cf366004614996565b612ab5565b61040a6106e2366004614b1f565b612bbd565b61040a6106f5366004614a8c565b612c45565b61041f610708366004614996565b612da8565b61041f6212750081565b610397610725366004614996565b612e09565b61041f620f424081565b61041f6702c68af0bb14000081565b61040a610751366004614a8c565b612ef1565b61037a610764366004614c1d565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61040a6107a0366004614a8c565b61304c565b6103df7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061085f57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b806108ab57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6060600080546108c090614c4b565b80601f01602080910402602001604051908101604052809291908181526020018280546108ec90614c4b565b80156109395780601f1061090e57610100808354040283529160200191610939565b820191906000526020600020905b81548152906001019060200180831161091c57829003601f168201915b5050505050905090565b60008181526002602052604081205481906001600160a01b0316610993576040517f2f9d01c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61099c8361312b565b90925090506109aa826131ef565b9150915091565b6000818152600260205260408120546001600160a01b0316610a405760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e000000000000000000000000000000000000000060648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b6000610a6782611ffa565b9050806001600160a01b0316836001600160a01b03161415610af15760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610a37565b336001600160a01b0382161480610b0d5750610b0d8133610764565b610b7f5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610a37565b610b898383613206565b505050565b60065460009074010000000000000000000000000000000000000000900460ff1615610bfc5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b610c058361328c565b60008281526007602052604090205460ff16610c4d576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c5883833361331e565b9392505050565b6000818152600260205260408120546001600160a01b0316610cad576040517f2f9d01c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b54610cb8610cdb565b6000848152600a6020526040902054610cd19190614cce565b6108ab9190614d3a565b600e54604080517f9703879c00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691639703879c9160048083019260209291908290030181865afa158015610d3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d629190614d4e565b600c60009054906101000a90046001600160a01b03166001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd99190614d4e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015610e56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e7a9190614d4e565b610e849190614d67565b610e8e9190614d67565b905090565b6006546001600160a01b03163314610eed5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b80610f24576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604090205460ff1615610f6d576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f3cc8bc2ec3ed67adce54f8d51791fff47b8bd6b911e75d2d5fefbde81e971d5c90610fd69083815260200190565b60405180910390a150565b610feb3382613373565b61105d5760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610a37565b610b8983838361347b565b60008061109060065460ff740100000000000000000000000000000000000000009091041690565b156110dd5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b84611114576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620f4240851015611151576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526007602052604090205460ff16611199576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0383166111d9576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011600081546111e890614d7f565b918290555091506112246001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481633308861366b565b600b54600090801561125e5786611239610cdb565b6112439190614db8565b61124d8289614cce565b6112579190614d3a565b9150611262565b8691505b6000848152600a60205260408120839055600b8054849290611285908490614d67565b9091555061129790508787868861373a565b92506112a385856139d8565b5050935093915050565b6006546001600160a01b031633146113075760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b600c60009054906101000a90046001600160a01b03166001600160a01b031663853828b66040518163ffffffff1660e01b81526004016020604051808303816000875af115801561135c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113809190614d4e565b50565b6006546001600160a01b031633146113dd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6113e56139f2565b600c60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611438573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145c9190614dcf565b156114ca57600c60009054906101000a90046001600160a01b03166001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156114b157600080fd5b505af11580156114c5573d6000803e3d6000fd5b505050505b600d546001600160a01b0316158015906115565750600d60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611532573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115569190614dcf565b156115c457600d60009054906101000a90046001600160a01b03166001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156115ab57600080fd5b505af11580156115bf573d6000803e3d6000fd5b505050505b600e60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611617573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163b9190614dcf565b156116a957600e60009054906101000a90046001600160a01b03166001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561169057600080fd5b505af11580156116a4573d6000803e3d6000fd5b505050505b600f60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117209190614dcf565b1561178e57600f60009054906101000a90046001600160a01b03166001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561177557600080fd5b505af1158015611789573d6000803e3d6000fd5b505050505b565b610b8983838360405180602001604052806000815250612bbd565b6006546001600160a01b031633146118055760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116611845576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6010546001600160a01b038281169116141561188d576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601054604080516001600160a01b03928316815291831660208301527f858040f45f3b8fa15a490ee8748c18344557eee85411d16032375a72ede42131910160405180910390a1601080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6006546001600160a01b031633146119685760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b0381166119a8576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d546001600160a01b03828116911614156119f0576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d54604080516001600160a01b03928316815291831660208301527f24062d083f038a9c1aeff4eaa632dd2d026ce766bb41fa307198b6ab6cd003f7910160405180910390a1600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60065460009074010000000000000000000000000000000000000000900460ff1615611adf5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b611ae88261328c565b611af182613ac4565b6000828152600a6020526040902054611b0c90839033613b83565b9050611b188233613be4565b60009182526008602052604082209190915590565b6006546001600160a01b03163314611b875760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116611bc7576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546001600160a01b0382811691161415611c0f576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e54604080516001600160a01b03928316815291831660208301527f73f2888686ab9a383b3e15e1af51c0bf844f02338c8d0b4b4e3f266a99c1e6ac910160405180910390a1600e80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6006546001600160a01b03163314611cea5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116611d2a576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c546001600160a01b0382811691161415611d72576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c60009054906101000a90046001600160a01b03166001600160a01b031663853828b66040518163ffffffff1660e01b81526004016020604051808303816000875af1925050508015611e01575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611dfe91810190614d4e565b60015b611e72573d808015611e2f576040519150601f19603f3d011682016040523d82523d6000602084013e611e34565b606091505b507ffe257ff0b8b9234a845b6da819fdd8bb73b1d3baf5ec0bfca0afdf884aaef54381604051611e649190614983565b60405180910390a150611e74565b505b600c54604080516001600160a01b03928316815291831660208301527fbffd2f20a06ca0304329080309bdd314339b2a5afe9927f8b3100220b661c947910160405180910390a1600c80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60065474010000000000000000000000000000000000000000900460ff1615611f605760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b600f546001600160a01b03163314611fa4576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015611fb457611fb48282613c40565b604080516001600160a01b0384168152602081018390527f86d1859fdb12afcb2875bb01d9996ad35d9dd55f62a87e76d9853161111b19ce910160405180910390a15050565b6000818152600260205260408120546001600160a01b0316806108ab5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201527f656e7420746f6b656e00000000000000000000000000000000000000000000006064820152608401610a37565b6000818152600260205260408120546001600160a01b03166120d3576040517f2f9d01c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009081526009602052604090205490565b6006546001600160a01b031633146121405760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b80612177576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c546040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0390911690632e1a7d4d90602401600060405180830381600087803b1580156121d657600080fd5b505af11580156121ea573d6000803e3d6000fd5b5050505050565b60006001600160a01b03821661226f5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610a37565b506001600160a01b031660009081526003602052604090205490565b6006546001600160a01b031633146122e55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b61178e6000613df6565b6006546001600160a01b031633146123495760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b600d546001600160a01b031661238b576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d54604080516001600160a01b039092168252600060208301527f24062d083f038a9c1aeff4eaa632dd2d026ce766bb41fa307198b6ab6cd003f7910160405180910390a1600d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6006546001600160a01b031633146124555760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b61245d613e60565b600c60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124d49190614dcf565b61254157600c60009054906101000a90046001600160a01b03166001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561252857600080fd5b505af115801561253c573d6000803e3d6000fd5b505050505b600d546001600160a01b0316158015906125cf5750600d60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125cd9190614dcf565b155b1561263d57600d60009054906101000a90046001600160a01b03166001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561262457600080fd5b505af1158015612638573d6000803e3d6000fd5b505050505b600e60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612690573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b49190614dcf565b61272157600e60009054906101000a90046001600160a01b03166001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561270857600080fd5b505af115801561271c573d6000803e3d6000fd5b505050505b600f60009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612774573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127989190614dcf565b61178e57600f60009054906101000a90046001600160a01b03166001600160a01b0316638456cb596040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561177557600080fd5b60008061281460065460ff740100000000000000000000000000000000000000009091041690565b156128615760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b600061286c84611ffa565b905060008061287a8661312b565b91509150806128b5576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128c0868333613b83565b93506128d08662eff1008561331e565b9450857f55cf5b0b0c4865ff48ccec25327df9c608efaf77250f54b9dbb4a3833100fb4d8560405161290491815260200190565b60405180910390a2505050915091565b6060600180546108c090614c4b565b6006546001600160a01b0316331461297d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b806129b4576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e60009054906101000a90046001600160a01b03166001600160a01b031663ce104f086040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612a0457600080fd5b505af1158015612a18573d6000803e3d6000fd5b5050600c54612a5692506001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811692501683613f32565b600c60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db06040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156121d657600080fd5b612ab1338383613f7b565b5050565b6006546001600160a01b03163314612b0f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b60008181526007602052604090205460ff16612b57576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517fa12571933ed68ec934e0a44f7702f6a8c284f907672c05b6eb02a6a1541a83a290610fd69083815260200190565b612bc73383613373565b612c395760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610a37565b61178984848484614068565b6006546001600160a01b03163314612c9f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116612cdf576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f546001600160a01b0382811691161415612d27576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f54604080516001600160a01b03928316815291831660208301527f4fb8c694740ad02d97e96c5bdd165d6e51d1a11e569be600ac432012b41ccf75910160405180910390a1600f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000818152600260205260408120546001600160a01b0316612df6576040517f2f9d01c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009081526008602052604090205490565b6000818152600260205260409020546060906001600160a01b0316612e965760405162461bcd60e51b815260206004820152602f60248201527f4552433732314d657461646174613a2055524920717565727920666f72206e6f60448201527f6e6578697374656e7420746f6b656e00000000000000000000000000000000006064820152608401610a37565b6000612ea06140f1565b90506000815111612ec05760405180602001604052806000815250610c58565b80612eca84614111565b604051602001612edb929190614dec565b6040516020818303038152906040529392505050565b6006546001600160a01b03163314612f4b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b038116612f8b576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c546001600160a01b0382811691161415612fd3576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c60009054906101000a90046001600160a01b03166001600160a01b031663853828b66040518163ffffffff1660e01b81526004016020604051808303816000875af1158015613028573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e729190614d4e565b6006546001600160a01b031633146130a65760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a37565b6001600160a01b0381166131225760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a37565b61138081613df6565b6000818152600860205260408120548190819061314c906212750090614d67565b9050428111156131625750600093849350915050565b600061317162093a8083614d67565b905060008142106131825781613184565b425b6000878152600a6020526040812054919250906131a9906702c68af0bb140000614cce565b9050670de0b6b3a764000062093a80826131c38786614db8565b6131cd9190614cce565b6131d79190614d3a565b6131e19190614d3a565b976001975095505050505050565b6000600b546131fc610cdb565b610cd19084614cce565b600081815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038416908117909155819061325382611ffa565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b3361329682611ffa565b6001600160a01b0316146132d6576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260086020526040902054421015611380576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061332a8483613be4565b61333e61333685610c5f565b84868561373a565b60405190915084907fd56ee5c2e47aa11e45be71e49c4d945f32b196e4d5689412bf45bb6ae6253d0190600090a29392505050565b6000818152600260205260408120546001600160a01b03166133fd5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201527f697374656e7420746f6b656e00000000000000000000000000000000000000006064820152608401610a37565b600061340883611ffa565b9050806001600160a01b0316846001600160a01b031614806134435750836001600160a01b0316613438846109b1565b6001600160a01b0316145b8061347357506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b826001600160a01b031661348e82611ffa565b6001600160a01b03161461350a5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201527f73206e6f74206f776e00000000000000000000000000000000000000000000006064820152608401610a37565b6001600160a01b0382166135855760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610a37565b613590838383614243565b61359b600082613206565b6001600160a01b03831660009081526003602052604081208054600192906135c4908490614db8565b90915550506001600160a01b03821660009081526003602052604081208054600192906135f2908490614d67565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6040516001600160a01b03808516602483015283166044820152606481018290526117899085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526142ae565b60006137468442614d67565b600084815260086020526040902055600d546001600160a01b031661376d57506000613473565b8461377a57506000613473565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000046d2a90153cd8f09464ca3a5605b6bbec9c2ff016001600160a01b0316906370a0823190602401602060405180830381865afa1580156137fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061381e9190614d4e565b600d546040517fd353b94c0000000000000000000000000000000000000000000000000000000081526004810189905260248101889052604481018790526001600160a01b03868116606483015292935091169063d353b94c906084016020604051808303816000875af115801561389a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138be9190614d4e565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290925060009082906001600160a01b037f00000000000000000000000046d2a90153cd8f09464ca3a5605b6bbec9c2ff0116906370a0823190602401602060405180830381865afa158015613943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139679190614d4e565b6139719190614db8565b90508281146139b6576040517f0c61d1f60000000000000000000000000000000000000000000000000000000081526004810184905260248101829052604401610a37565b82156139ce5760008581526009602052604090208390555b5050949350505050565b612ab1828260405180602001604052806000815250614393565b60065474010000000000000000000000000000000000000000900460ff16613a5c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a37565b600680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000613acf82611ffa565b9050613add81600084614243565b613ae8600083613206565b6001600160a01b0381166000908152600360205260408120805460019290613b11908490614db8565b909155505060008281526002602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6000613b8e836131ef565b90508015613ba057613ba08282613c40565b6000848152600a602052604081208054859290613bbe908490614db8565b9250508190555082600b6000828254613bd79190614db8565b9091555090949350505050565b60008281526009602052604090205480613bfd57505050565b600083815260096020526040812055610b896001600160a01b037f00000000000000000000000046d2a90153cd8f09464ca3a5605b6bbec9c2ff01168383613f32565b600e60009054906101000a90046001600160a01b03166001600160a01b031663ce104f086040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613c9057600080fd5b505af1158015613ca4573d6000803e3d6000fd5b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600092507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b031691506370a0823190602401602060405180830381865afa158015613d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d4c9190614d4e565b905080821115613dc257600c546001600160a01b0316632e1a7d4d613d718385614db8565b6040518263ffffffff1660e01b8152600401613d8f91815260200190565b600060405180830381600087803b158015613da957600080fd5b505af1158015613dbd573d6000803e3d6000fd5b505050505b610b896001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48168484613f32565b600680546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60065474010000000000000000000000000000000000000000900460ff1615613ecb5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b600680547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613aa73390565b6040516001600160a01b038316602482015260448101829052610b899084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016136b8565b816001600160a01b0316836001600160a01b03161415613fdd5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610a37565b6001600160a01b0383811660008181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61407384848461347b565b61407f8484848461441c565b6117895760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610a37565b6060604051806060016040528060258152602001614ed460259139905090565b60608161415157505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561417b578061416581614d7f565b91506141749050600a83614d3a565b9150614155565b60008167ffffffffffffffff81111561419657614196614af0565b6040519080825280601f01601f1916602001820160405280156141c0576020820181803683370190505b5090505b8415613473576141d5600183614db8565b91506141e2600a86614e1b565b6141ed906030614d67565b60f81b81838151811061420257614202614e2f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061423c600a86614d3a565b94506141c4565b60065474010000000000000000000000000000000000000000900460ff1615610b895760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b6000614303826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145d59092919063ffffffff16565b805190915015610b8957808060200190518101906143219190614dcf565b610b895760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a37565b61439d83836145e4565b6143aa600084848461441c565b610b895760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610a37565b60006001600160a01b0384163b156145cd576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063150b7a0290614479903390899088908890600401614e5e565b6020604051808303816000875af19250505080156144d2575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526144cf91810190614e9a565b60015b614582573d808015614500576040519150601f19603f3d011682016040523d82523d6000602084013e614505565b606091505b50805161457a5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610a37565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149050613473565b506001613473565b6060613473848460008561474a565b6001600160a01b03821661463a5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610a37565b6000818152600260205260409020546001600160a01b03161561469f5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610a37565b6146ab60008383614243565b6001600160a01b03821660009081526003602052604081208054600192906146d4908490614d67565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6060824710156147c25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a37565b843b6148105760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a37565b600080866001600160a01b0316858760405161482c9190614eb7565b60006040518083038185875af1925050503d8060008114614869576040519150601f19603f3d011682016040523d82523d6000602084013e61486e565b606091505b509150915061487e828286614889565b979650505050505050565b60608315614898575081610c58565b8251156148a85782518084602001fd5b8160405162461bcd60e51b8152600401610a379190614983565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461138057600080fd5b60006020828403121561490257600080fd5b8135610c58816148c2565b60005b83811015614928578181015183820152602001614910565b838111156117895750506000910152565b6000815180845261495181602086016020860161490d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c586020830184614939565b6000602082840312156149a857600080fd5b5035919050565b6001600160a01b038116811461138057600080fd5b600080604083850312156149d757600080fd5b82356149e2816149af565b946020939093013593505050565b60008060408385031215614a0357600080fd5b50508035926020909101359150565b600080600060608486031215614a2757600080fd5b8335614a32816149af565b92506020840135614a42816149af565b929592945050506040919091013590565b600080600060608486031215614a6857600080fd5b83359250602084013591506040840135614a81816149af565b809150509250925092565b600060208284031215614a9e57600080fd5b8135610c58816149af565b801515811461138057600080fd5b60008060408385031215614aca57600080fd5b8235614ad5816149af565b91506020830135614ae581614aa9565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060008060808587031215614b3557600080fd5b8435614b40816149af565b93506020850135614b50816149af565b925060408501359150606085013567ffffffffffffffff80821115614b7457600080fd5b818701915087601f830112614b8857600080fd5b813581811115614b9a57614b9a614af0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715614be057614be0614af0565b816040528281528a6020848701011115614bf957600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215614c3057600080fd5b8235614c3b816149af565b91506020830135614ae5816149af565b600181811c90821680614c5f57607f821691505b60208210811415614c99577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614d0657614d06614c9f565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614d4957614d49614d0b565b500490565b600060208284031215614d6057600080fd5b5051919050565b60008219821115614d7a57614d7a614c9f565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614db157614db1614c9f565b5060010190565b600082821015614dca57614dca614c9f565b500390565b600060208284031215614de157600080fd5b8151610c5881614aa9565b60008351614dfe81846020880161490d565b835190830190614e1281836020880161490d565b01949350505050565b600082614e2a57614e2a614d0b565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006001600160a01b03808716835280861660208401525083604083015260806060830152614e906080830184614939565b9695505050505050565b600060208284031215614eac57600080fd5b8151610c58816148c2565b60008251614ec981846020870161490d565b919091019291505056fe68747470733a2f2f6e66742e736865726c6f636b2e78797a2f6170692f6d61696e6e65742fa26469706673582212200e87f14c7fb0f108d25dd551de75d1569a694919aeacae263b7f059ed8fe374264736f6c634300080a0033

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

000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000046d2a90153cd8f09464ca3a5605b6bbec9c2ff0100000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000f02d3a6288d998b412ce749cff244c8ef799f5820000000000000000000000005775f32787656e77dd99f20f4e478ddc85fdb31b000000000000000000000000666b8ebfbf4d5f0ce56962a25635cff563f131610000000000000000000000003d0b8a0a10835ab9b0f0beb54c5400b8aacaa1d3000000000000000000000000feedd254ae4b7c44a0472bb836b813ce4625eb8400000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000020536865726c6f636b205374616b696e6720506f736974696f6e204e46542d56310000000000000000000000000000000000000000000000000000000000000008534845522d504f5300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000eff1000000000000000000000000000000000000000000000000000000000001dfe200

-----Decoded View---------------
Arg [0] : _token (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : _sher (address): 0x46D2A90153cd8F09464CA3a5605B6BBeC9C2fF01
Arg [2] : _name (string): Sherlock Staking Position NFT-V1
Arg [3] : _symbol (string): SHER-POS
Arg [4] : _yieldStrategy (address): 0xF02d3A6288D998B412ce749cfF244c8ef799f582
Arg [5] : _sherDistributionManager (address): 0x5775F32787656E77dd99f20F4E478DdC85fdB31b
Arg [6] : _nonStakersAddress (address): 0x666B8EbFbF4D5f0CE56962a25635CfF563F13161
Arg [7] : _sherlockProtocolManager (address): 0x3d0b8A0A10835Ab9b0f0BeB54C5400B8aAcaa1D3
Arg [8] : _sherlockClaimManager (address): 0xFeEDD254ae4B7c44A0472Bb836b813Ce4625Eb84
Arg [9] : _initialstakingPeriods (uint256[]): 15724800,31449600

-----Encoded View---------------
17 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 00000000000000000000000046d2a90153cd8f09464ca3a5605b6bbec9c2ff01
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [4] : 000000000000000000000000f02d3a6288d998b412ce749cff244c8ef799f582
Arg [5] : 0000000000000000000000005775f32787656e77dd99f20f4e478ddc85fdb31b
Arg [6] : 000000000000000000000000666b8ebfbf4d5f0ce56962a25635cff563f13161
Arg [7] : 0000000000000000000000003d0b8a0a10835ab9b0f0beb54c5400b8aacaa1d3
Arg [8] : 000000000000000000000000feedd254ae4b7c44a0472bb836b813ce4625eb84
Arg [9] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [11] : 536865726c6f636b205374616b696e6720506f736974696f6e204e46542d5631
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [13] : 534845522d504f53000000000000000000000000000000000000000000000000
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [15] : 0000000000000000000000000000000000000000000000000000000000eff100
Arg [16] : 0000000000000000000000000000000000000000000000000000000001dfe200


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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