ETH Price: $2,345.86 (-2.97%)

Contract

0xFeEDD254ae4B7c44A0472Bb836b813Ce4625Eb84
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer Ownersh...143102272022-03-02 22:17:15927 days ago1646259435IN
0xFeEDD254...e4625Eb84
0 ETH0.0018537365
Set Sherlock Cor...143101522022-03-02 21:58:26927 days ago1646258306IN
0xFeEDD254...e4625Eb84
0 ETH0.0029372265
0x60a06040143101412022-03-02 21:56:09927 days ago1646258169IN
 Create: SherlockClaimManager
0 ETH0.2738787365

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SherlockClaimManager

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 20000 runs

Other Settings:
default evmVersion
File 1 of 25 : SherlockClaimManager.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
/******************************************************************************/

// This contract contains the logic for handling claims
// The idea is that the first level of handling a claim is the Sherlock Protocol Claims Committee (SPCC)(a multisig)
// If a protocol agent doesn't like that result, they can escalate the claim to UMA's Optimistic Oracle (OO), who will be the final decision
// We also build in a multisig (controlled by UMA) to give the final approve to pay out after the OO approves a claim

import './Manager.sol';
import '../interfaces/managers/ISherlockClaimManager.sol';
import '../interfaces/managers/ISherlockProtocolManager.sol';
import '../interfaces/UMAprotocol/SkinnyOptimisticOracleInterface.sol';

import '@openzeppelin/contracts/security/ReentrancyGuard.sol';

/// @dev expects 6 decimals input tokens
contract SherlockClaimManager is ISherlockClaimManager, ReentrancyGuard, Manager {
  using SafeERC20 for IERC20;

  /// @dev at time of writing, the escalation cost will be 22.2k
  /// assuming BOND = 9600 and UMA's final fee = 1500
  /// UMA's final fee can be changed in the future, which may result in lower or higher required staked amounts for escalating a claim.
  /// The actual amount is 2 * (BOND + UMA's final fee), because:
  /// 1. The first half is charged when calling UMA.requestAndProposePriceFor()
  /// 2. The second half is charged when calling UMA.disputePriceFor()
  /// UMA's fee can be found here: https://github.com/UMAprotocol/protocol/blob/master/packages/core/contracts/oracle/implementation/Store.sol#L131)
  uint256 internal constant BOND = 9_600 * 10**6;

  // The amount of time the protocol agent has to escalate a claim
  uint256 public constant ESCALATE_TIME = 4 weeks;

  // The UMA Halt Operator (UMAHO) is the multisig (controlled by UMA) who gives final approval to pay out a claim
  // After the OO has voted to pay out
  // This variable represents the amount of time during which UMAHO can block a claim that was approved by the OO
  // After this time period, the claim (which was approved by the OO) is inferred to be approved by UMAHO as well
  uint256 public constant UMAHO_TIME = 24 hours;

  // The amount of time the Sherlock Protocol Claims Committee (SPCC) gets to decide on a claim
  // If no action is taken by SPCC during this time, then the protocol agent can escalate the decision to the UMA OO
  uint256 public constant SPCC_TIME = 7 days;

  // A pre-defined amount of time for the proposed price ($0) to be disputed within the OO
  // Note This value is not important as we immediately dispute the proposed price
  // 7200 represents 2 hours
  uint256 internal constant LIVENESS = 7200;

  // This is how UMA will know that Sherlock is requesting a decision from the OO
  // This is "SHERLOCK_CLAIM" in hex value
  bytes32 public constant override UMA_IDENTIFIER =
    bytes32(0x534845524c4f434b5f434c41494d000000000000000000000000000000000000);

  uint256 public constant MAX_CALLBACKS = 4;

  // The Optimistic Oracle contract that we interact with
  SkinnyOptimisticOracleInterface public constant UMA =
    SkinnyOptimisticOracleInterface(0xeE3Afe347D5C74317041E2618C49534dAf887c24);

  // USDC
  IERC20 public constant TOKEN = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);

  // The address of the multisig controlled by UMA that can emergency halt a claim that was approved by the OO
  address public override umaHaltOperator;
  // The address of the multisig controlled by Sherlock advisors who make the first judgment on a claim
  address public immutable override sherlockProtocolClaimsCommittee;

  // Takes a protocol's internal ID as a key and whether or not the protocol has a claim active as the value
  // Note Each protocol can only have one claim active at a time (this prevents spam)
  mapping(bytes32 => bool) public protocolClaimActive;

  // A protocol's public claim ID is simply incremented by 1 from the last claim ID made by any protocol (1, 2, 3, etc.)
  // A protocol's internal ID is the keccak256() of a protocol's ancillary data field
  // A protocol's ancillary data field will contain info like the hash of the protocol's coverage agreement (each will be unique)
  // The public ID (1, 2, 3, etc.) is easy to track while the internal ID is used for interacting with UMA
  mapping(uint256 => bytes32) internal publicToInternalID;

  // Opposite of the last field, allows us to move between a protocol's public ID and internal ID
  mapping(bytes32 => uint256) internal internalToPublicID;

  // Protocol's internal ID is the key, active claim is the value
  // Claim object is initialized in startClaim() below
  // See ISherlockClaimManager.sol for Claim struct
  mapping(bytes32 => Claim) internal claims_;

  // The last claim ID we used for a claim (ID is incremented by 1 each time)
  uint256 internal lastClaimID;

  // A request object used in the UMA OO
  SkinnyOptimisticOracleInterface.Request private umaRequest;

  // An array of contracts that implement the callback provided in this contract
  ISherlockClaimManagerCallbackReceiver[] public claimCallbacks;

  // Used for callbacks on UMA functions
  // This modifier is used for a function being called by the OO contract, requires this contract as caller
  // Requires the OO contract to pass in the Sherlock identifier
  modifier onlyUMA(bytes32 identifier) {
    if (identifier != UMA_IDENTIFIER) revert InvalidArgument();
    if (msg.sender != address(UMA)) revert InvalidSender();
    _;
  }

  // Only the Sherlock Claims Committee multisig can call a function with this modifier
  modifier onlySPCC() {
    if (msg.sender != sherlockProtocolClaimsCommittee) revert InvalidSender();
    _;
  }

  // Only the UMA Halt Operator multisig can call a function with this modifier
  modifier onlyUMAHO() {
    if (msg.sender != umaHaltOperator) revert InvalidSender();
    _;
  }

  // We pass in the contract addresses (both will be multisigs) in the constructor
  constructor(address _umaho, address _spcc) {
    if (_umaho == address(0)) revert ZeroArgument();
    if (_spcc == address(0)) revert ZeroArgument();

    umaHaltOperator = _umaho;
    sherlockProtocolClaimsCommittee = _spcc;
  }

  // Checks to see if a claim can be escalated to the UMA OO
  // Claim must be either
  // 1) Denied by SPCC and within 4 weeks after denial
  // 2) Pending by SPCC but beyond the designated time window for SPCC to respond
  function _isEscalateState(State _oldState, uint256 updated) internal view returns (bool) {
    if (_oldState == State.SpccDenied && block.timestamp <= updated + ESCALATE_TIME) return true;

    uint256 spccDeadline = updated + SPCC_TIME;
    if (
      _oldState == State.SpccPending &&
      spccDeadline < block.timestamp &&
      block.timestamp <= spccDeadline + ESCALATE_TIME
    ) {
      return true;
    }
    return false;
  }

  // Checks to see if a claim can be paid out
  // Will be paid out if:
  // 1) SPCC approved it
  // 2) UMA OO approved it and there is no UMAHO anymore
  // 3) UMA OO approved it and the designated window for the UMAHO to block it has passed
  function _isPayoutState(State _oldState, uint256 updated) internal view returns (bool) {
    if (_oldState == State.SpccApproved) return true;

    // If there is no UMA Halt Operator, then it can be paid out on UmaApproved state
    if (umaHaltOperator == address(0)) {
      if (_oldState == State.UmaApproved) return true;
    } else {
      // If there IS a nonzero UMAHO address, must wait for UMAHO halt period to pass
      if (_oldState == State.UmaApproved && updated + UMAHO_TIME < block.timestamp) return true;
    }
    return false;
  }

  function _isCleanupState(State _oldState) internal pure returns (bool) {
    if (_oldState == State.SpccDenied) return true;
    if (_oldState == State.SpccPending) return true;
    return false;
  }

  // Deletes the data associated with a claim (after claim has reached its final state)
  // _claimIdentifier is the internal claim ID
  function _cleanUpClaim(bytes32 _claimIdentifier) internal {
    // Protocol no longer has an active claim associated with it
    delete protocolClaimActive[claims_[_claimIdentifier].protocol];
    // Claim object is deleted
    delete claims_[_claimIdentifier];

    uint256 publicID = internalToPublicID[_claimIdentifier];
    // Deletes the public and internal ID key mappings
    delete publicToInternalID[publicID];
    delete internalToPublicID[_claimIdentifier];
  }

  // Each claim has a state that represents what part of the claims process it is in
  // _claimIdentifier is the internal claim ID
  // _state represents the state to which a protocol's state field will be changed
  // See ISherlockClaimManager.sol for the State enum
  function _setState(bytes32 _claimIdentifier, State _state) internal returns (State _oldState) {
    // retrieves the Claim object
    Claim storage claim = claims_[_claimIdentifier];
    // retrieves the current state (which we preemptively set to the old state)
    _oldState = claim.state;

    emit ClaimStatusChanged(internalToPublicID[_claimIdentifier], _oldState, _state);

    // If the new state is NonExistent, then we clean up this claim (delete the claim effectively)
    // Else we update the state to the new state and record the last updated timestamp
    if (_state == State.NonExistent) {
      _cleanUpClaim(_claimIdentifier);
    } else {
      claims_[_claimIdentifier].state = _state;
      claims_[_claimIdentifier].updated = block.timestamp;
    }
  }

  // Allows us to remove the UMA Halt Operator multisig address if we decide we no longer need UMAHO's services
  /// @notice gov is able to renounce the role
  function renounceUmaHaltOperator() external override onlyOwner {
    if (umaHaltOperator == address(0)) revert InvalidConditions();

    delete umaHaltOperator;
    emit UMAHORenounced();
  }

  // Returns the Claim struct for a given claim ID (function takes public ID but converts to internal ID)
  function claim(uint256 _claimID) external view override returns (Claim memory claim_) {
    bytes32 id_ = publicToInternalID[_claimID];
    if (id_ == bytes32(0)) revert InvalidArgument();

    claim_ = claims_[id_];
    if (claim_.state == State.NonExistent) revert InvalidArgument();
  }

  // This function allows a new contract to be added that will implement PreCorePayoutCallback()
  // The intention of this callback is to allow other contracts to trigger payouts, etc. when Sherlock triggers one
  // This would be helpful for a reinsurer who should pay out when Sherlock pays out
  // Data is passed to the "reinsurer" so it can know if it should pay out and how much
  /// @dev only add trusted and gas verified callbacks.
  function addCallback(ISherlockClaimManagerCallbackReceiver _callback)
    external
    onlyOwner
    nonReentrant
  {
    if (address(_callback) == address(0)) revert ZeroArgument();
    // Checks to see if the max amount of callback contracts has been reached
    if (claimCallbacks.length == MAX_CALLBACKS) revert InvalidState();
    // Checks to see if this callback contract already exists
    for (uint256 i; i < claimCallbacks.length; i++) {
      if (claimCallbacks[i] == _callback) revert InvalidArgument();
    }

    claimCallbacks.push(_callback);
    emit CallbackAdded(_callback);
  }

  // This removes a contract from the claimCallbacks array
  function removeCallback(ISherlockClaimManagerCallbackReceiver _callback, uint256 _index)
    external
    onlyOwner
    nonReentrant
  {
    if (address(_callback) == address(0)) revert ZeroArgument();
    // If the index and the callback contract don't line up, revert
    if (claimCallbacks[_index] != _callback) revert InvalidArgument();

    // Move last index to index of _callback
    // Creates a copy of the last index value and pastes it over the _index value
    claimCallbacks[_index] = claimCallbacks[claimCallbacks.length - 1];
    // Remove last index (because it is now a duplicate)
    claimCallbacks.pop();
    emit CallbackRemoved(_callback);
  }

  /// @notice Cleanup claim if escalation is not pursued
  /// @param _protocol protocol ID
  /// @param _claimID public claim ID
  /// @dev Retrieves current protocol agent for cleanup
  /// @dev State is either SpccPending or SpccDenied
  function cleanUp(bytes32 _protocol, uint256 _claimID) external whenNotPaused {
    if (_protocol == bytes32(0)) revert ZeroArgument();
    if (_claimID == uint256(0)) revert ZeroArgument();

    // Gets the instance of the protocol manager contract
    ISherlockProtocolManager protocolManager = sherlockCore.sherlockProtocolManager();
    // Gets the protocol agent associated with the protocol ID passed in
    address agent = protocolManager.protocolAgent(_protocol);
    // Caller of this function must be the protocol agent address associated with the protocol ID passed in
    if (msg.sender != agent) revert InvalidSender();

    bytes32 claimIdentifier = publicToInternalID[_claimID];
    // If there is no active claim
    if (claimIdentifier == bytes32(0)) revert InvalidArgument();

    Claim storage claim = claims_[claimIdentifier];
    // verify if claim belongs to protocol agent
    if (claim.protocol != _protocol) revert InvalidArgument();

    State _oldState = _setState(claimIdentifier, State.Cleaned);
    if (_isCleanupState(_oldState) == false) revert InvalidState();
    if (_setState(claimIdentifier, State.NonExistent) != State.Cleaned) revert InvalidState();
  }

  /// @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
  /// @dev This is done because a protocols coverage can end after an exploit, either wilfully or forcefully.
  /// @dev The protocol agent is still active for 7 days after coverage ends, so a claim can still be submitted.
  /// @dev Approved claims after the 7 day period will still be paid, where the amount will be sent to the recevier.
  function startClaim(
    bytes32 _protocol,
    uint256 _amount,
    address _receiver,
    uint32 _timestamp,
    bytes memory ancillaryData
  ) external override nonReentrant whenNotPaused {
    if (_protocol == bytes32(0)) revert ZeroArgument();
    if (_amount == uint256(0)) revert ZeroArgument();
    if (_receiver == address(0)) revert ZeroArgument();
    if (_timestamp == uint32(0)) revert ZeroArgument();
    if (_timestamp >= block.timestamp) revert InvalidArgument();
    if (ancillaryData.length == 0) revert ZeroArgument();
    if (address(sherlockCore) == address(0)) revert InvalidConditions();
    // Protocol must not already have another claim active
    if (protocolClaimActive[_protocol]) revert ClaimActive();

    // Creates the internal ID for this claim
    bytes32 claimIdentifier = keccak256(ancillaryData);
    // State for this newly created claim must be equal to the default state (NonExistent)
    if (claims_[claimIdentifier].state != State.NonExistent) revert InvalidArgument();

    // Gets the instance of the protocol manager contract
    ISherlockProtocolManager protocolManager = sherlockCore.sherlockProtocolManager();
    // Gets the protocol agent associated with the protocol ID passed in
    address agent = protocolManager.protocolAgent(_protocol);
    // Caller of this function must be the protocol agent address associated with the protocol ID passed in
    if (msg.sender != agent) revert InvalidSender();

    // Gets the current and previous coverage amount for this protocol
    (uint256 current, uint256 previous) = protocolManager.coverageAmounts(_protocol);
    // The max amount a protocol can claim is the higher of the current and previous coverage amounts
    uint256 maxClaim = current > previous ? current : previous;
    // True if a protocol is claiming based on its previous coverage amount (only used in event emission)
    // Current coverage takes precedence over the previous one, which means the only case this is true
    // is when claimed amount is greater than current coverage.
    bool prevCoverage = _amount > current;
    // Requires the amount claimed is less than or equal to the higher of the current and previous coverage amounts
    if (_amount > maxClaim) revert InvalidArgument();

    // Increments the last claim ID by 1 to get the public claim ID
    // Note initial claimID will be 1
    uint256 claimID = ++lastClaimID;
    // Protocol now has an active claim
    protocolClaimActive[_protocol] = true;
    // Sets the mappings for public and internal claim IDs
    publicToInternalID[claimID] = claimIdentifier;
    internalToPublicID[claimIdentifier] = claimID;

    // Initializes a Claim object and adds it to claims_ mapping
    // Created and updated fields are set to current time
    // State is updated to SpccPending (waiting on SPCC decision now)
    claims_[claimIdentifier] = Claim(
      block.timestamp,
      block.timestamp,
      msg.sender,
      _protocol,
      _amount,
      _receiver,
      _timestamp,
      State.SpccPending,
      ancillaryData
    );

    emit ClaimCreated(claimID, _protocol, _amount, _receiver, prevCoverage);
    emit ClaimStatusChanged(claimID, State.NonExistent, State.SpccPending);
  }

  // Only SPCC can call this
  // SPCC approves the claim and it can now be paid out
  // Requires that the last state of the claim was SpccPending
  function spccApprove(uint256 _claimID) external override whenNotPaused onlySPCC nonReentrant {
    bytes32 claimIdentifier = publicToInternalID[_claimID];
    if (claimIdentifier == bytes32(0)) revert InvalidArgument();

    if (_setState(claimIdentifier, State.SpccApproved) != State.SpccPending) revert InvalidState();
  }

  // Only SPCC can call this
  // SPCC denies the claim and now the protocol agent can escalate to UMA OO if they desire
  function spccRefuse(uint256 _claimID) external override whenNotPaused onlySPCC nonReentrant {
    bytes32 claimIdentifier = publicToInternalID[_claimID];
    if (claimIdentifier == bytes32(0)) revert InvalidArgument();

    if (_setState(claimIdentifier, State.SpccDenied) != State.SpccPending) revert InvalidState();
  }

  // If SPCC denied (or didn't respond to) the claim, a protocol agent can now escalate it to UMA's OO
  /// @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 Requires the caller to be the account that initially started the claim
  // Amount sent needs to be at least equal to the BOND amount required
  function escalate(uint256 _claimID, uint256 _amount)
    external
    override
    nonReentrant
    whenNotPaused
  {
    if (_amount < BOND) revert InvalidArgument();

    // Gets the internal ID of the claim
    bytes32 claimIdentifier = publicToInternalID[_claimID];
    if (claimIdentifier == bytes32(0)) revert InvalidArgument();

    // Retrieves the claim struct
    Claim storage claim = claims_[claimIdentifier];
    // Requires the caller to be the account that initially started the claim
    if (msg.sender != claim.initiator) revert InvalidSender();

    // Timestamp when claim was last updated
    uint256 updated = claim.updated;
    // Sets the state to UmaPriceProposed
    State _oldState = _setState(claimIdentifier, State.UmaPriceProposed);

    // Can this claim be updated (based on its current state)? If no, revert
    if (_isEscalateState(_oldState, updated) == false) revert InvalidState();

    // Transfers the bond amount from the protocol agent to this address
    TOKEN.safeTransferFrom(msg.sender, address(this), _amount);
    // Approves the OO contract to spend the bond amount
    TOKEN.safeApprove(address(UMA), _amount);

    // Sherlock protocol proposes a claim amount of $0 to the UMA OO to begin with
    // This line https://github.com/UMAprotocol/protocol/blob/master/packages/core/contracts/oracle/implementation/SkinnyOptimisticOracle.sol#L585
    // Will result in disputeSuccess=true if the DVM resolved price != 0
    // Note: The resolved price needs to exactly match the claim amount
    // Otherwise the `umaApproved` in our settled callback will be false
    UMA.requestAndProposePriceFor(
      UMA_IDENTIFIER, // Sherlock ID so UMA knows the request came from Sherlock
      claim.timestamp, // Timestamp to identify the request
      claim.ancillaryData, // Ancillary data such as the coverage agreement
      TOKEN, // USDC
      0, // Reward is 0, Sherlock handles rewards on its own
      BOND, // Cost of making a request to the UMA OO (as decided by Sherlock)
      LIVENESS, // Proposal liveness
      address(sherlockCore), // If escalated claim fails, bond amount gets sent to sherlockCore
      0 // price
    );

    // If the state is not equal to ReadyToProposeUmaDispute, revert
    // Then set the new state to UmaDisputeProposed
    // Note State gets set to ReadyToProposeUmaDispute in the callback function from requestAndProposePriceFor()
    if (_setState(claimIdentifier, State.UmaDisputeProposed) != State.ReadyToProposeUmaDispute) {
      revert InvalidState();
    }

    // The protocol agent is now disputing Sherlock's proposed claim amount of $0
    UMA.disputePriceFor(
      UMA_IDENTIFIER, // Sherlock ID so UMA knows the request came from Sherlock
      claim.timestamp, // Timestamp to identify the request
      claim.ancillaryData, // Ancillary data such as the coverage agreement
      umaRequest, // Refers to the original request made by Sherlock in requestAndProposePriceFor()
      msg.sender, // Protocol agent, known as the disputer (the one who is disputing Sherlock's $0 proposed claim amount)
      address(this) // This contract's address is the requester (Sherlock made the original request and proposed $0 claim amount)
    );

    // State gets updated to UmaPending in the disputePriceFor() callback (priceDisputed())
    if (claim.state != State.UmaPending) revert InvalidState();

    // Deletes the original request made by Sherlock
    delete umaRequest;
    // Approves the OO to spend $0
    // This is just out of caution, don't want UMA to be approved for any amount of tokens they shouldn't be
    TOKEN.safeApprove(address(UMA), 0);
    // Checks for remaining balance in the contract
    uint256 remaining = TOKEN.balanceOf(address(this));
    // Sends remaining balance to the protocol agent
    // A protocol agent should be able to send the exact amount to avoid the extra gas from this function
    if (remaining != 0) TOKEN.safeTransfer(msg.sender, remaining);
  }

  // Checks to make sure a payout is valid, then calls the core Sherlock payout function
  /// @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
  // We are ok with spending the extra time to wait for the UMAHO time to expire before paying out
  // We could have UMAHO multisig send a tx to confirm the payout (payout would happen sooner),
  // But doesn't seem worth it to save half a day or so
  function payoutClaim(uint256 _claimID) external override nonReentrant whenNotPaused {
    bytes32 claimIdentifier = publicToInternalID[_claimID];
    if (claimIdentifier == bytes32(0)) revert InvalidArgument();

    Claim storage claim = claims_[claimIdentifier];
    // Only the claim initiator can call this, and payout gets sent to receiver address
    if (msg.sender != claim.initiator) revert InvalidSender();

    bytes32 protocol = claim.protocol;
    // Address to receive the payout
    // Note We could make the receiver a param in this function, but we want it to be known asap
    // Can find and correct problems if the receiver is specified when the claim is initiated
    address receiver = claim.receiver;
    // Amount (in USDC) to be paid out
    uint256 amount = claim.amount;
    // Time when claim was last updated
    uint256 updated = claim.updated;

    // Sets new state to NonExistent as the claim is over once it is paid out
    State _oldState = _setState(claimIdentifier, State.NonExistent);
    // Checks to make sure this claim can be paid out
    if (_isPayoutState(_oldState, updated) == false) revert InvalidState();

    // Calls the PreCorePayoutCallback function on any contracts in claimCallbacks
    for (uint256 i; i < claimCallbacks.length; i++) {
      claimCallbacks[i].PreCorePayoutCallback(protocol, _claimID, amount);
    }

    emit ClaimPayout(_claimID, receiver, amount);

    // We could potentially transfer more than `amount` in case balance > amount
    // We are leaving this as is for simplicity's sake
    // We don't expect to have tokens in this contract unless a reinsurer is providing them for a payout
    // In which case they should provide the exact amount, and balance == amount is true
    uint256 balance = TOKEN.balanceOf(address(this));
    if (balance != 0) TOKEN.safeTransfer(receiver, balance);
    if (balance < amount) sherlockCore.payoutClaim(receiver, amount - balance);
  }

  /// @notice UMAHO is able to execute a halt if the state is UmaApproved and state was updated less than UMAHO_TIME ago
  // Once the UMAHO_TIME is up, UMAHO can still halt the claim, but only if the claim hasn't been paid out yet
  function executeHalt(uint256 _claimID) external override whenNotPaused onlyUMAHO nonReentrant {
    bytes32 claimIdentifier = publicToInternalID[_claimID];
    if (claimIdentifier == bytes32(0)) revert InvalidArgument();

    // Sets state of claim to nonexistent, reverts if the old state was anything but UmaApproved
    if (_setState(claimIdentifier, State.Halted) != State.UmaApproved) revert InvalidState();
    if (_setState(claimIdentifier, State.NonExistent) != State.Halted) revert InvalidState();

    emit ClaimHalted(_claimID);
  }

  //
  // UMA callbacks
  //

  // Once requestAndProposePriceFor() is executed in UMA's contracts, this function gets called
  // We change the claim's state from UmaPriceProposed to ReadyToProposeUmaDispute
  // Then, the next callback in the process, disputePriceFor(), gets called by the UMA's contract.
  // @note Does not have reentrancy protection because it is called by the OO contract which is non-reentrant.
  function priceProposed(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    SkinnyOptimisticOracleInterface.Request memory request
  ) external override whenNotPaused onlyUMA(identifier) {
    bytes32 claimIdentifier = keccak256(ancillaryData);

    Claim storage claim = claims_[claimIdentifier];
    if (claim.updated != block.timestamp) revert InvalidConditions();

    // Sets state to ReadyToProposeUmaDispute
    if (_setState(claimIdentifier, State.ReadyToProposeUmaDispute) != State.UmaPriceProposed) {
      revert InvalidState();
    }
    // Sets global umaRequest variable to the request coming from this price proposal
    umaRequest = request;
  }

  // Once disputePriceFor() is executed in UMA's contracts, this function gets called
  // We change the claim's state from UmaDisputeProposed to UmaPending
  // Then, the next callback in the process, priceSettled(), gets called by the UMA's contract.
  // @note Does not have reentrancy protection because it is called by the OO contract which is non-reentrant.
  function priceDisputed(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    SkinnyOptimisticOracleInterface.Request memory request
  ) external override whenNotPaused onlyUMA(identifier) {
    bytes32 claimIdentifier = keccak256(ancillaryData);

    Claim storage claim = claims_[claimIdentifier];
    if (claim.updated != block.timestamp) revert InvalidConditions();

    // Sets state to UmaPending
    if (_setState(claimIdentifier, State.UmaPending) != State.UmaDisputeProposed) {
      revert InvalidState();
    }
  }

  // Once priceSettled() is executed in UMA's contracts, this function gets called
  // UMA OO gives back a resolved price (either 0 or claim.amount) and
  // Claim's state is changed to either UmaApproved or UmaDenied
  // If UmaDenied, the claim is dead and state is immediately changed to NonExistent and cleaned up
  /// @dev still want to capture settled price in a paused state. Otherwise claim is stuck.
  function priceSettled(
    bytes32 identifier,
    uint32 timestamp,
    bytes memory ancillaryData,
    SkinnyOptimisticOracleInterface.Request memory request
  ) external override onlyUMA(identifier) nonReentrant {
    bytes32 claimIdentifier = keccak256(ancillaryData);

    Claim storage claim = claims_[claimIdentifier];

    // Retrives the resolved price for this claim (either 0 if Sherlock wins, or the amount of the claim as proposed by the protocol agent)
    uint256 resolvedPrice = uint256(request.resolvedPrice);
    // UMA approved the claim if the resolved price is equal to the claim amount set by the protocol agent
    bool umaApproved = resolvedPrice == claim.amount;

    // If UMA approves the claim, set state to UmaApproved
    // If UMA denies, set state to UmaDenied, then to NonExistent (deletes the claim data)
    if (umaApproved) {
      if (_setState(claimIdentifier, State.UmaApproved) != State.UmaPending) revert InvalidState();
    } else {
      if (_setState(claimIdentifier, State.UmaDenied) != State.UmaPending) revert InvalidState();
      if (_setState(claimIdentifier, State.NonExistent) != State.UmaDenied) revert InvalidState();
    }
  }
}

File 2 of 25 : Manager.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/utils/SafeERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/security/Pausable.sol';

import '../interfaces/managers/IManager.sol';

abstract contract Manager is IManager, Ownable, Pausable {
  using SafeERC20 for IERC20;

  address private constant DEPLOYER = 0x1C11bE636415973520DdDf1b03822b4e2930D94A;
  ISherlock internal sherlockCore;

  modifier onlySherlockCore() {
    if (msg.sender != address(sherlockCore)) revert InvalidSender();
    _;
  }

  /// @notice Set sherlock core address
  /// @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 emits `SherlockCoreSet`
  function setSherlockCoreAddress(ISherlock _sherlock) external override {
    if (address(_sherlock) == address(0)) revert ZeroArgument();
    // 31337 is of the Hardhat network blockchain
    if (block.chainid != 31337 && msg.sender != DEPLOYER) revert InvalidSender();

    if (address(sherlockCore) != address(0)) revert InvalidConditions();
    sherlockCore = _sherlock;

    emit SherlockCoreSet(_sherlock);
  }

  // Internal function to send tokens remaining in a contract to the receiver address
  function _sweep(address _receiver, IERC20[] memory _extraTokens) internal {
    // Loops through the extra tokens (ERC20) provided and sends all of them to the receiver address
    for (uint256 i; i < _extraTokens.length; i++) {
      IERC20 token = _extraTokens[i];
      token.safeTransfer(_receiver, token.balanceOf(address(this)));
    }
    // Sends any remaining ETH to the receiver address (as long as receiver address is payable)
    (bool success, ) = _receiver.call{ value: address(this).balance }('');
    if (success == false) revert InvalidConditions();
  }

  function pause() external onlySherlockCore {
    _pause();
  }

  function unpause() external onlySherlockCore {
    _unpause();
  }
}

File 3 of 25 : 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 4 of 25 : 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 5 of 25 : 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 6 of 25 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 7 of 25 : 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 8 of 25 : 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 9 of 25 : 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 10 of 25 : 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 11 of 25 : 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 12 of 25 : 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 13 of 25 : 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 14 of 25 : 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 15 of 25 : 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 16 of 25 : 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 25 : 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 25 : 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 25 : 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 25 : 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 21 of 25 : 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 22 of 25 : 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 23 of 25 : 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 24 of 25 : 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 25 of 25 : 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":"address","name":"_umaho","type":"address"},{"internalType":"address","name":"_spcc","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ClaimActive","type":"error"},{"inputs":[],"name":"InvalidArgument","type":"error"},{"inputs":[],"name":"InvalidConditions","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"InvalidState","type":"error"},{"inputs":[],"name":"ZeroArgument","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISherlockClaimManagerCallbackReceiver","name":"callback","type":"address"}],"name":"CallbackAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISherlockClaimManagerCallbackReceiver","name":"callback","type":"address"}],"name":"CallbackRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"claimID","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"protocol","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"bool","name":"previousCoverageUsed","type":"bool"}],"name":"ClaimCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"claimID","type":"uint256"}],"name":"ClaimHalted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"claimID","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimPayout","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"claimID","type":"uint256"},{"indexed":false,"internalType":"enum ISherlockClaimManager.State","name":"previousState","type":"uint8"},{"indexed":false,"internalType":"enum ISherlockClaimManager.State","name":"currentState","type":"uint8"}],"name":"ClaimStatusChanged","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 ISherlock","name":"sherlock","type":"address"}],"name":"SherlockCoreSet","type":"event"},{"anonymous":false,"inputs":[],"name":"UMAHORenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"ESCALATE_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CALLBACKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPCC_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UMA","outputs":[{"internalType":"contract SkinnyOptimisticOracleInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UMAHO_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UMA_IDENTIFIER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISherlockClaimManagerCallbackReceiver","name":"_callback","type":"address"}],"name":"addCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimID","type":"uint256"}],"name":"claim","outputs":[{"components":[{"internalType":"uint256","name":"created","type":"uint256"},{"internalType":"uint256","name":"updated","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"bytes32","name":"protocol","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"enum ISherlockClaimManager.State","name":"state","type":"uint8"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"internalType":"struct ISherlockClaimManager.Claim","name":"claim_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"claimCallbacks","outputs":[{"internalType":"contract ISherlockClaimManagerCallbackReceiver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_protocol","type":"bytes32"},{"internalType":"uint256","name":"_claimID","type":"uint256"}],"name":"cleanUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimID","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"escalate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimID","type":"uint256"}],"name":"executeHalt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"uint256","name":"_claimID","type":"uint256"}],"name":"payoutClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"address","name":"disputer","type":"address"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"bool","name":"settled","type":"bool"},{"internalType":"int256","name":"proposedPrice","type":"int256"},{"internalType":"int256","name":"resolvedPrice","type":"int256"},{"internalType":"uint256","name":"expirationTime","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"finalFee","type":"uint256"},{"internalType":"uint256","name":"bond","type":"uint256"},{"internalType":"uint256","name":"customLiveness","type":"uint256"}],"internalType":"struct SkinnyOptimisticOracleInterface.Request","name":"request","type":"tuple"}],"name":"priceDisputed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"address","name":"disputer","type":"address"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"bool","name":"settled","type":"bool"},{"internalType":"int256","name":"proposedPrice","type":"int256"},{"internalType":"int256","name":"resolvedPrice","type":"int256"},{"internalType":"uint256","name":"expirationTime","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"finalFee","type":"uint256"},{"internalType":"uint256","name":"bond","type":"uint256"},{"internalType":"uint256","name":"customLiveness","type":"uint256"}],"internalType":"struct SkinnyOptimisticOracleInterface.Request","name":"request","type":"tuple"}],"name":"priceProposed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"identifier","type":"bytes32"},{"internalType":"uint32","name":"timestamp","type":"uint32"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"},{"components":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"address","name":"disputer","type":"address"},{"internalType":"contract IERC20","name":"currency","type":"address"},{"internalType":"bool","name":"settled","type":"bool"},{"internalType":"int256","name":"proposedPrice","type":"int256"},{"internalType":"int256","name":"resolvedPrice","type":"int256"},{"internalType":"uint256","name":"expirationTime","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"finalFee","type":"uint256"},{"internalType":"uint256","name":"bond","type":"uint256"},{"internalType":"uint256","name":"customLiveness","type":"uint256"}],"internalType":"struct SkinnyOptimisticOracleInterface.Request","name":"request","type":"tuple"}],"name":"priceSettled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"protocolClaimActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ISherlockClaimManagerCallbackReceiver","name":"_callback","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"removeCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceUmaHaltOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISherlock","name":"_sherlock","type":"address"}],"name":"setSherlockCoreAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sherlockProtocolClaimsCommittee","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimID","type":"uint256"}],"name":"spccApprove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimID","type":"uint256"}],"name":"spccRefuse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_protocol","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint32","name":"_timestamp","type":"uint32"},{"internalType":"bytes","name":"ancillaryData","type":"bytes"}],"name":"startClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"umaHaltOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b5060405162004c3b38038062004c3b833981016040819052620000349162000136565b60016000556200004433620000c7565b6001805460ff60a01b191690556001600160a01b038216620000795760405163b7852ebb60e01b815260040160405180910390fd5b6001600160a01b038116620000a15760405163b7852ebb60e01b815260040160405180910390fd5b600380546001600160a01b0319166001600160a01b03938416179055166080526200016e565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b03811681146200013157600080fd5b919050565b600080604083850312156200014a57600080fd5b620001558362000119565b9150620001656020840162000119565b90509250929050565b608051614aa362000198600039600081816104a401528181612e7a01526131c30152614aa36000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c8063715018a61161010f578063c5efc2c6116100a2578063f2fde38b11610071578063f2fde38b1461044e578063f64a1e2f14610461578063f678d9241461047c578063f870715b1461049f57600080fd5b8063c5efc2c614610416578063ca70fb7614610420578063db2546ed14610433578063f2037d741461044657600080fd5b806382bfefc8116100de57806382bfefc8146103c25780638456cb59146103dd5780638da5cb5b146103e5578063acd59ceb1461040357600080fd5b8063715018a614610381578063724f1814146103895780637a1047dd1461039c578063827e7f3e146103af57600080fd5b80633f4ba83a116101875780635c975abb116101565780635c975abb1461030e5780635f620f851461033d57806366917de014610347578063702388fa1461036e57600080fd5b80633f4ba83a1461029b5780633f8c2b4d146102a357806347619afa146102e85780634e3a3334146102fb57600080fd5b806311bad40a116101c357806311bad40a14610242578063195689f6146102555780633365783614610268578063379607f51461027b57600080fd5b8063017eb8d9146101f5578063058f62b2146102105780630c0374b81461021a5780630d13fa5a1461022f575b600080fd5b6101fd600481565b6040519081526020015b60405180910390f35b6101fd62093a8081565b61022d6102283660046140a4565b6104c6565b005b61022d61023d3660046140c6565b610b5c565b61022d610250366004614242565b610fe1565b61022d61026336600461436d565b6111a8565b61022d610276366004614399565b611497565b61028e6102893660046140c6565b611732565b6040516102079190614496565b61022d6119a1565b6003546102c39073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610207565b61022d6102f6366004614559565b6119fc565b6102c36103093660046140c6565b6122a2565b60015474010000000000000000000000000000000000000000900460ff165b6040519015158152602001610207565b6101fd6224ea0081565b6101fd7f534845524c4f434b5f434c41494d00000000000000000000000000000000000081565b61022d61037c3660046140c6565b6122d9565b61022d61250d565b61022d610397366004614242565b61257e565b61022d6103aa3660046140a4565b612830565b61022d6103bd366004614242565b612b6f565b6102c373a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b61022d612d9e565b60015473ffffffffffffffffffffffffffffffffffffffff166102c3565b61022d6104113660046140c6565b612df7565b6101fd6201518081565b61022d61042e366004614399565b612fcd565b61022d6104413660046140c6565b613140565b61022d6132c5565b61022d61045c366004614399565b6133ce565b6102c373ee3afe347d5c74317041e2618c49534daf887c2481565b61032d61048a3660046140c6565b60046020526000908152604090205460ff1681565b6102c37f000000000000000000000000000000000000000000000000000000000000000081565b6002600054141561051e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260005560015474010000000000000000000000000000000000000000900460ff161561058e5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b64023c3460008110156105cd576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205480610613576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409020600281015473ffffffffffffffffffffffffffffffffffffffff163314610674576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181015460006106868460046134ca565b905061069281836135f3565b6106c8576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106e873a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48333088613693565b61071b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ee3afe347d5c74317041e2618c49534daf887c2487613775565b60058301546002546040517faf355d1e00000000000000000000000000000000000000000000000000000000815273ee3afe347d5c74317041e2618c49534daf887c249263af355d1e926107f6927f534845524c4f434b5f434c41494d0000000000000000000000000000000000009274010000000000000000000000000000000000000000900463ffffffff169160068a019173a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489160009164023c34600091611c209173ffffffffffffffffffffffffffffffffffffffff9091169084906004016146f2565b6020604051808303816000875af1158015610815573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108399190614766565b5060056108478560066134ca565b600b811115610858576108586143b6565b1461088f576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60058301546040517f9ce320c800000000000000000000000000000000000000000000000000000000815273ee3afe347d5c74317041e2618c49534daf887c2491639ce320c891610930917f534845524c4f434b5f434c41494d000000000000000000000000000000000000917401000000000000000000000000000000000000000090910463ffffffff169060068901906009903390309060040161477f565b6020604051808303816000875af115801561094f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109739190614766565b50600760058401547801000000000000000000000000000000000000000000000000900460ff16600b8111156109ab576109ab6143b6565b146109e2576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600a80549091169055600b80547fffffffffffffffffffffff0000000000000000000000000000000000000000001690556000600c819055600d819055600e819055600f819055601081905560118190556012819055610a989073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489073ee3afe347d5c74317041e2618c49534daf887c2490613775565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48906370a0823190602401602060405180830381865afa158015610b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b279190614766565b90508015610b4e57610b4e73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4833836138e2565b505060016000555050505050565b60026000541415610baf5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260005560015474010000000000000000000000000000000000000000900460ff1615610c1f5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b60008181526005602052604090205480610c65576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409020600281015473ffffffffffffffffffffffffffffffffffffffff163314610cc6576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600381015460058201546004830154600184015473ffffffffffffffffffffffffffffffffffffffff909216916000610cff87826134ca565b9050610d0b8183613938565b610d41576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b601354811015610e0f5760138181548110610d6157610d616148d0565b6000918252602090912001546040517f1c45dde000000000000000000000000000000000000000000000000000000000815260048101889052602481018b90526044810186905273ffffffffffffffffffffffffffffffffffffffff90911690631c45dde090606401600060405180830381600087803b158015610de457600080fd5b505af1158015610df8573d6000803e3d6000fd5b505050508080610e079061492e565b915050610d44565b506040805189815273ffffffffffffffffffffffffffffffffffffffff861660208201529081018490527fd821d0aeb565103d334a4682afaddb77a21313f36e8886593baaf6b2594e198c9060600160405180910390a16040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48906370a0823190602401602060405180830381865afa158015610ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef59190614766565b90508015610f1c57610f1c73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4886836138e2565b83811015610fd15760025473ffffffffffffffffffffffffffffffffffffffff16636240901186610f4d8488614967565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b158015610fb857600080fd5b505af1158015610fcc573d6000803e3d6000fd5b505050505b5050600160005550505050505050565b60015474010000000000000000000000000000000000000000900460ff161561104c5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b837f534845524c4f434b5f434c41494d00000000000000000000000000000000000081146110a6576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ee3afe347d5c74317041e2618c49534daf887c24146110f3576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516020808501919091206000818152600790925260409091206001810154421461114a576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60066111578360076134ca565b600b811115611168576111686143b6565b1461119f576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461120f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b600260005414156112625760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260005573ffffffffffffffffffffffffffffffffffffffff82166112b4576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16601382815481106112de576112de6148d0565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614611337576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013805461134790600190614967565b81548110611357576113576148d0565b6000918252602090912001546013805473ffffffffffffffffffffffffffffffffffffffff9092169183908110611390576113906148d0565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060138054806113e9576113e961497e565b60008281526020908190207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908301810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590910190915560405173ffffffffffffffffffffffffffffffffffffffff841681527ffb6c51f2be3d7773b505e38661540db3f8479f63b5d173fe2ecae1edc7562b5d91015b60405180910390a150506001600055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146114fe5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b600260005414156115515760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260005573ffffffffffffffffffffffffffffffffffffffff81166115a3576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601354600414156115e0576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b601354811015611683578173ffffffffffffffffffffffffffffffffffffffff1660138281548110611617576116176148d0565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff161415611671576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061167b8161492e565b9150506115e3565b50601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f3206984d30c94bcf064cb1df53d334a1fe97a7931023e3c1ea98fa76a973cc809060200160405180910390a1506001600055565b6117816040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529060e08201908152602001606081525090565b600082815260056020526040902054806117c7576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602090815260409182902082516101208101845281548152600182015492810192909252600281015473ffffffffffffffffffffffffffffffffffffffff908116938301939093526003810154606083015260048101546080830152600581015492831660a083015274010000000000000000000000000000000000000000830463ffffffff1660c0830152909160e08301907801000000000000000000000000000000000000000000000000900460ff16600b811115611891576118916143b6565b600b8111156118a2576118a26143b6565b81526020016006820180546118b6906145cd565b80601f01602080910402602001604051908101604052809291908181526020018280546118e2906145cd565b801561192f5780601f106119045761010080835404028352916020019161192f565b820191906000526020600020905b81548152906001019060200180831161191257829003601f168201915b50505050508152505091506000600b81111561194d5761194d6143b6565b8260e00151600b811115611963576119636143b6565b141561199b576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50919050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146119f2576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119fa6139e2565b565b60026000541415611a4f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260005560015474010000000000000000000000000000000000000000900460ff1615611abf5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b84611af6576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83611b2d576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316611b7a576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8216611bb7576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428263ffffffff1610611bf6576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051611c2e576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025473ffffffffffffffffffffffffffffffffffffffff16611c7d576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008581526004602052604090205460ff1615611cc6576040517f2ae8a9f800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020820120600080828152600760205260409020600501547801000000000000000000000000000000000000000000000000900460ff16600b811115611d1057611d106143b6565b14611d47576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600254604080517f863a43d5000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163863a43d59160048083019260209291908290030181865afa158015611db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ddb91906149ad565b6040517fc46060d40000000000000000000000000000000000000000000000000000000081526004810189905290915060009073ffffffffffffffffffffffffffffffffffffffff83169063c46060d490602401602060405180830381865afa158015611e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7091906149ad565b90503373ffffffffffffffffffffffffffffffffffffffff821614611ec1576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fcaef4f1b00000000000000000000000000000000000000000000000000000000815260048101899052600090819073ffffffffffffffffffffffffffffffffffffffff85169063caef4f1b906024016040805180830381865afa158015611f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5491906149ca565b915091506000818311611f675781611f69565b825b9050828a11818b1115611fa8576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600860008154611fb99061492e565b91905081905590506001600460008f815260200190815260200160002060006101000a81548160ff02191690831515021790555087600560008381526020019081526020016000208190555080600660008a8152602001908152602001600020819055506040518061012001604052804281526020014281526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018e81526020018d81526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b63ffffffff1681526020016001600b811115612098576120986143b6565b815260209081018b905260008a8152600782526040908190208351815591830151600183015582015160028201805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116179055606083015160038301556080830151600483015560a083015160058301805460c086015163ffffffff1674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090911692909316919091179190911780825560e084015191907fffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000083600b8111156121cf576121cf6143b6565b021790555061010082015180516121f0916006840191602090910190613fd5565b505060408051838152602081018f905273ffffffffffffffffffffffffffffffffffffffff8e1681830152841515606082015290518f92507fa9554fcda31212dfb9fc1180820bd0bffc960baad3d9d1daa6c361ccfa8477be9181900360800190a2807f2d8b91cd39b91d452a6c29034de86e9ac2ff4936f8fe3a2aa319a662f4206ece600060016040516122869291906149ee565b60405180910390a2505060016000555050505050505050505050565b601381815481106122b257600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60015474010000000000000000000000000000000000000000900460ff16156123445760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b60035473ffffffffffffffffffffffffffffffffffffffff163314612395576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260005414156123e85760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260009081558181526005602052604090205480612433576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600861244082600a6134ca565b600b811115612451576124516143b6565b14612488576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a6124958260006134ca565b600b8111156124a6576124a66143b6565b146124dd576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518281527f1d5afae6999ee19e72635fe41333d99c8dc5dd052e08fcc93058b0706364421d90602001611486565b60015473ffffffffffffffffffffffffffffffffffffffff1633146125745760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b6119fa6000613ac1565b60015474010000000000000000000000000000000000000000900460ff16156125e95760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b837f534845524c4f434b5f434c41494d0000000000000000000000000000000000008114612643576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ee3afe347d5c74317041e2618c49534daf887c2414612690576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251602080850191909120600081815260079092526040909120600181015442146126e7576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60046126f48360056134ca565b600b811115612705576127056143b6565b1461273c576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505081516009805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556020840151600a8054918416919092161790556040830151600b80546060860151151574010000000000000000000000000000000000000000027fffffffffffffffffffffff0000000000000000000000000000000000000000009091169290931691909117919091179055506080810151600c5560a0810151600d5560c0810151600e5560e0810151600f556101008101516010556101208101516011556101400151601255505050565b60015474010000000000000000000000000000000000000000900460ff161561289b5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b816128d2576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80612909576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600254604080517f863a43d5000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163863a43d59160048083019260209291908290030181865afa158015612979573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299d91906149ad565b6040517fc46060d40000000000000000000000000000000000000000000000000000000081526004810185905290915060009073ffffffffffffffffffffffffffffffffffffffff83169063c46060d490602401602060405180830381865afa158015612a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a3291906149ad565b90503373ffffffffffffffffffffffffffffffffffffffff821614612a83576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205480612ac9576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260076020526040902060038101548614612b14576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612b2183600b6134ca565b9050612b2c81613b38565b612b62576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b6111578460006134ca565b837f534845524c4f434b5f434c41494d0000000000000000000000000000000000008114612bc9576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ee3afe347d5c74317041e2618c49534daf887c2414612c16576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026000541415612c695760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b6002600090815583516020808601919091208083526007909152604090912060a0840151600482015481148015612cf4576007612ca78560086134ca565b600b811115612cb857612cb86143b6565b14612cef576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fd1565b6007612d018560096134ca565b600b811115612d1257612d126143b6565b14612d49576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009612d568560006134ca565b600b811115612d6757612d676143b6565b14610fd1576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025473ffffffffffffffffffffffffffffffffffffffff163314612def576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119fa613b86565b60015474010000000000000000000000000000000000000000900460ff1615612e625760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612ed1576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026000541415612f245760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260009081558181526005602052604090205480612f6f576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001612f7c8260026134ca565b600b811115612f8d57612f8d6143b6565b14612fc4576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506001600055565b73ffffffffffffffffffffffffffffffffffffffff811661301a576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46617a6914158015613040575033731c11be636415973520dddf1b03822b4e2930d94a14155b15613077576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025473ffffffffffffffffffffffffffffffffffffffff16156130c7576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527ff200116515c6d70d53a45299bb7eba08ef985ec08bfe0baf31ad73907308a3189060200160405180910390a150565b60015474010000000000000000000000000000000000000000900460ff16156131ab5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461321a576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600054141561326d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b6002600090815581815260056020526040902054806132b8576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001612f7c8260036134ca565b60015473ffffffffffffffffffffffffffffffffffffffff16331461332c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b60035473ffffffffffffffffffffffffffffffffffffffff1661337b576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040517f36a0933bcc1c8c7ed7e8978ca49d792479a0262a8411115d4c90a07a784cf7cd90600090a1565b60015473ffffffffffffffffffffffffffffffffffffffff1633146134355760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b73ffffffffffffffffffffffffffffffffffffffff81166134be5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610515565b6134c781613ac1565b50565b60008281526007602090815260408083206005810154600690935292819020549051780100000000000000000000000000000000000000000000000090920460ff1692917f2d8b91cd39b91d452a6c29034de86e9ac2ff4936f8fe3a2aa319a662f4206ece9061353d90859087906149ee565b60405180910390a2600083600b811115613559576135596143b6565b141561356d5761356884613c58565b6135ec565b600084815260076020526040902060050180548491907fffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000083600b8111156135d1576135d16143b6565b02179055506000848152600760205260409020426001909101555b5092915050565b6000600383600b811115613609576136096143b6565b148015613622575061361e6224ea0083614a09565b4211155b1561362f5750600161368d565b600061363e62093a8084614a09565b9050600184600b811115613654576136546143b6565b14801561366057504281105b801561367857506136746224ea0082614a09565b4211155b1561368757600191505061368d565b60009150505b92915050565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261376f9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613d45565b50505050565b80158061381557506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156137ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138139190614766565b155b6138875760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610515565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526138dd9084907f095ea7b300000000000000000000000000000000000000000000000000000000906064016136ed565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526138dd9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016136ed565b6000600283600b81111561394e5761394e6143b6565b141561395c5750600161368d565b60035473ffffffffffffffffffffffffffffffffffffffff166139a057600883600b81111561398d5761398d6143b6565b141561399b5750600161368d565b6139d9565b600883600b8111156139b4576139b46143b6565b1480156139cc5750426139ca6201518084614a09565b105b156139d95750600161368d565b50600092915050565b60015474010000000000000000000000000000000000000000900460ff16613a4c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610515565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000600382600b811115613b4e57613b4e6143b6565b1415613b5c57506001919050565b600182600b811115613b7057613b706143b6565b1415613b7e57506001919050565b506000919050565b60015474010000000000000000000000000000000000000000900460ff1615613bf15760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613a973390565b60008181526007602081815260408084206003810180548652600480855292862080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905586865293909252838255600182018490556002820180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055918390559081018290556005810180547fffffffffffffff0000000000000000000000000000000000000000000000000016905590613d1c6006830182614059565b505060008181526006602081815260408084208054855260058352908420849055938352529055565b6000613da7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613e379092919063ffffffff16565b8051909150156138dd5780806020019051810190613dc59190614a21565b6138dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610515565b6060613e468484600085613e50565b90505b9392505050565b606082471015613ec85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610515565b843b613f165760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610515565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613f3f9190614a3e565b60006040518083038185875af1925050503d8060008114613f7c576040519150601f19603f3d011682016040523d82523d6000602084013e613f81565b606091505b5091509150613f91828286613f9c565b979650505050505050565b60608315613fab575081613e49565b825115613fbb5782518084602001fd5b8160405162461bcd60e51b81526004016105159190614a5a565b828054613fe1906145cd565b90600052602060002090601f0160209004810192826140035760008555614049565b82601f1061401c57805160ff1916838001178555614049565b82800160010185558215614049579182015b8281111561404957825182559160200191906001019061402e565b5061405592915061408f565b5090565b508054614065906145cd565b6000825580601f10614075575050565b601f0160209004906000526020600020908101906134c791905b5b808211156140555760008155600101614090565b600080604083850312156140b757600080fd5b50508035926020909101359150565b6000602082840312156140d857600080fd5b5035919050565b803563ffffffff811681146140f357600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561414b5761414b6140f8565b60405290565b600082601f83011261416257600080fd5b813567ffffffffffffffff8082111561417d5761417d6140f8565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156141c3576141c36140f8565b816040528381528660208588010111156141dc57600080fd5b836020870160208301376000602085830101528094505050505092915050565b73ffffffffffffffffffffffffffffffffffffffff811681146134c757600080fd5b80356140f3816141fc565b80151581146134c757600080fd5b80356140f381614229565b6000806000808486036101c081121561425a57600080fd5b8535945061426a602087016140df565b9350604086013567ffffffffffffffff81111561428657600080fd5b61429288828901614151565b935050610160807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0830112156142c757600080fd5b6142cf614127565b91506142dd6060880161421e565b82526142eb6080880161421e565b60208301526142fc60a0880161421e565b604083015261430d60c08801614237565b606083015260e087013560808301526101008088013560a08401526101208089013560c0850152610140808a013560e0860152838a0135838601526101808a0135828601526101a08a013581860152505050508091505092959194509250565b6000806040838503121561438057600080fd5b823561438b816141fc565b946020939093013593505050565b6000602082840312156143ab57600080fd5b8135613e49816141fc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600c811061441c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60005b8381101561443b578181015183820152602001614423565b8381111561376f5750506000910152565b60008151808452614464816020860160208601614420565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081528151602082015260208201516040820152600060408301516144d4606084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608301516080830152608083015160a083015260a083015161451060c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015163ffffffff811660e08401525060e0830151610100614537818501836143e5565b84015161012084810152905061455161014084018261444c565b949350505050565b600080600080600060a0868803121561457157600080fd5b8535945060208601359350604086013561458a816141fc565b9250614598606087016140df565b9150608086013567ffffffffffffffff8111156145b457600080fd5b6145c088828901614151565b9150509295509295909350565b600181811c908216806145e157607f821691505b6020821081141561199b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8054600090600181811c908083168061463557607f831692505b6020808410821415614670577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8388526020880182801561468b57600181146146ba576146e5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008716825282820197506146e5565b60008981526020902060005b878110156146df578154848201529086019084016146c6565b83019850505b5050505050505092915050565b60006101208b835263ffffffff8b1660208401528060408401526147188184018b61461b565b73ffffffffffffffffffffffffffffffffffffffff998a1660608501526080840198909852505060a081019490945260c084019290925290931660e082015261010001919091529392505050565b60006020828403121561477857600080fd5b5051919050565b600061020088835263ffffffff881660208401528060408401526147a58184018861461b565b9150506147e7606083016147cd875473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff169052565b600185015473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff8116608084015250600285015473ffffffffffffffffffffffffffffffffffffffff811660a084015261485460c0840160ff8360a01c1615159052565b50600385015460e0830152600485015461010083015260058501546101208301526006850154610140830152600785015461016083015260088501546101808301526009909401546101a082015273ffffffffffffffffffffffffffffffffffffffff9283166101c082015291166101e0909101529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614960576149606148ff565b5060010190565b600082821015614979576149796148ff565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000602082840312156149bf57600080fd5b8151613e49816141fc565b600080604083850312156149dd57600080fd5b505080516020909101519092909150565b604081016149fc82856143e5565b613e4960208301846143e5565b60008219821115614a1c57614a1c6148ff565b500190565b600060208284031215614a3357600080fd5b8151613e4981614229565b60008251614a50818460208701614420565b9190910192915050565b602081526000613e49602083018461444c56fea2646970667358221220c74c1b742575f5b0b7e63fae01462ba1ef7765d74e92a33ecd6b80acce5d9cbc64736f6c634300080a00330000000000000000000000008fcc879036fc8e45395ade7d4ef739200037695c0000000000000000000000004fcf6aa323a92eb92a58025e821f393da6c41bd6

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101f05760003560e01c8063715018a61161010f578063c5efc2c6116100a2578063f2fde38b11610071578063f2fde38b1461044e578063f64a1e2f14610461578063f678d9241461047c578063f870715b1461049f57600080fd5b8063c5efc2c614610416578063ca70fb7614610420578063db2546ed14610433578063f2037d741461044657600080fd5b806382bfefc8116100de57806382bfefc8146103c25780638456cb59146103dd5780638da5cb5b146103e5578063acd59ceb1461040357600080fd5b8063715018a614610381578063724f1814146103895780637a1047dd1461039c578063827e7f3e146103af57600080fd5b80633f4ba83a116101875780635c975abb116101565780635c975abb1461030e5780635f620f851461033d57806366917de014610347578063702388fa1461036e57600080fd5b80633f4ba83a1461029b5780633f8c2b4d146102a357806347619afa146102e85780634e3a3334146102fb57600080fd5b806311bad40a116101c357806311bad40a14610242578063195689f6146102555780633365783614610268578063379607f51461027b57600080fd5b8063017eb8d9146101f5578063058f62b2146102105780630c0374b81461021a5780630d13fa5a1461022f575b600080fd5b6101fd600481565b6040519081526020015b60405180910390f35b6101fd62093a8081565b61022d6102283660046140a4565b6104c6565b005b61022d61023d3660046140c6565b610b5c565b61022d610250366004614242565b610fe1565b61022d61026336600461436d565b6111a8565b61022d610276366004614399565b611497565b61028e6102893660046140c6565b611732565b6040516102079190614496565b61022d6119a1565b6003546102c39073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610207565b61022d6102f6366004614559565b6119fc565b6102c36103093660046140c6565b6122a2565b60015474010000000000000000000000000000000000000000900460ff165b6040519015158152602001610207565b6101fd6224ea0081565b6101fd7f534845524c4f434b5f434c41494d00000000000000000000000000000000000081565b61022d61037c3660046140c6565b6122d9565b61022d61250d565b61022d610397366004614242565b61257e565b61022d6103aa3660046140a4565b612830565b61022d6103bd366004614242565b612b6f565b6102c373a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b61022d612d9e565b60015473ffffffffffffffffffffffffffffffffffffffff166102c3565b61022d6104113660046140c6565b612df7565b6101fd6201518081565b61022d61042e366004614399565b612fcd565b61022d6104413660046140c6565b613140565b61022d6132c5565b61022d61045c366004614399565b6133ce565b6102c373ee3afe347d5c74317041e2618c49534daf887c2481565b61032d61048a3660046140c6565b60046020526000908152604090205460ff1681565b6102c37f0000000000000000000000004fcf6aa323a92eb92a58025e821f393da6c41bd681565b6002600054141561051e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260005560015474010000000000000000000000000000000000000000900460ff161561058e5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b64023c3460008110156105cd576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205480610613576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409020600281015473ffffffffffffffffffffffffffffffffffffffff163314610674576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181015460006106868460046134ca565b905061069281836135f3565b6106c8576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106e873a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48333088613693565b61071b73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ee3afe347d5c74317041e2618c49534daf887c2487613775565b60058301546002546040517faf355d1e00000000000000000000000000000000000000000000000000000000815273ee3afe347d5c74317041e2618c49534daf887c249263af355d1e926107f6927f534845524c4f434b5f434c41494d0000000000000000000000000000000000009274010000000000000000000000000000000000000000900463ffffffff169160068a019173a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489160009164023c34600091611c209173ffffffffffffffffffffffffffffffffffffffff9091169084906004016146f2565b6020604051808303816000875af1158015610815573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108399190614766565b5060056108478560066134ca565b600b811115610858576108586143b6565b1461088f576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60058301546040517f9ce320c800000000000000000000000000000000000000000000000000000000815273ee3afe347d5c74317041e2618c49534daf887c2491639ce320c891610930917f534845524c4f434b5f434c41494d000000000000000000000000000000000000917401000000000000000000000000000000000000000090910463ffffffff169060068901906009903390309060040161477f565b6020604051808303816000875af115801561094f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109739190614766565b50600760058401547801000000000000000000000000000000000000000000000000900460ff16600b8111156109ab576109ab6143b6565b146109e2576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600980547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116909155600a80549091169055600b80547fffffffffffffffffffffff0000000000000000000000000000000000000000001690556000600c819055600d819055600e819055600f819055601081905560118190556012819055610a989073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489073ee3afe347d5c74317041e2618c49534daf887c2490613775565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48906370a0823190602401602060405180830381865afa158015610b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b279190614766565b90508015610b4e57610b4e73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4833836138e2565b505060016000555050505050565b60026000541415610baf5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260005560015474010000000000000000000000000000000000000000900460ff1615610c1f5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b60008181526005602052604090205480610c65576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600760205260409020600281015473ffffffffffffffffffffffffffffffffffffffff163314610cc6576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600381015460058201546004830154600184015473ffffffffffffffffffffffffffffffffffffffff909216916000610cff87826134ca565b9050610d0b8183613938565b610d41576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b601354811015610e0f5760138181548110610d6157610d616148d0565b6000918252602090912001546040517f1c45dde000000000000000000000000000000000000000000000000000000000815260048101889052602481018b90526044810186905273ffffffffffffffffffffffffffffffffffffffff90911690631c45dde090606401600060405180830381600087803b158015610de457600080fd5b505af1158015610df8573d6000803e3d6000fd5b505050508080610e079061492e565b915050610d44565b506040805189815273ffffffffffffffffffffffffffffffffffffffff861660208201529081018490527fd821d0aeb565103d334a4682afaddb77a21313f36e8886593baaf6b2594e198c9060600160405180910390a16040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48906370a0823190602401602060405180830381865afa158015610ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef59190614766565b90508015610f1c57610f1c73a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4886836138e2565b83811015610fd15760025473ffffffffffffffffffffffffffffffffffffffff16636240901186610f4d8488614967565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b158015610fb857600080fd5b505af1158015610fcc573d6000803e3d6000fd5b505050505b5050600160005550505050505050565b60015474010000000000000000000000000000000000000000900460ff161561104c5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b837f534845524c4f434b5f434c41494d00000000000000000000000000000000000081146110a6576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ee3afe347d5c74317041e2618c49534daf887c24146110f3576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516020808501919091206000818152600790925260409091206001810154421461114a576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60066111578360076134ca565b600b811115611168576111686143b6565b1461119f576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461120f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b600260005414156112625760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260005573ffffffffffffffffffffffffffffffffffffffff82166112b4576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16601382815481106112de576112de6148d0565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614611337576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013805461134790600190614967565b81548110611357576113576148d0565b6000918252602090912001546013805473ffffffffffffffffffffffffffffffffffffffff9092169183908110611390576113906148d0565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060138054806113e9576113e961497e565b60008281526020908190207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff908301810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590910190915560405173ffffffffffffffffffffffffffffffffffffffff841681527ffb6c51f2be3d7773b505e38661540db3f8479f63b5d173fe2ecae1edc7562b5d91015b60405180910390a150506001600055565b60015473ffffffffffffffffffffffffffffffffffffffff1633146114fe5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b600260005414156115515760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260005573ffffffffffffffffffffffffffffffffffffffff81166115a3576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601354600414156115e0576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b601354811015611683578173ffffffffffffffffffffffffffffffffffffffff1660138281548110611617576116176148d0565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff161415611671576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061167b8161492e565b9150506115e3565b50601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f3206984d30c94bcf064cb1df53d334a1fe97a7931023e3c1ea98fa76a973cc809060200160405180910390a1506001600055565b6117816040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529060e08201908152602001606081525090565b600082815260056020526040902054806117c7576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602090815260409182902082516101208101845281548152600182015492810192909252600281015473ffffffffffffffffffffffffffffffffffffffff908116938301939093526003810154606083015260048101546080830152600581015492831660a083015274010000000000000000000000000000000000000000830463ffffffff1660c0830152909160e08301907801000000000000000000000000000000000000000000000000900460ff16600b811115611891576118916143b6565b600b8111156118a2576118a26143b6565b81526020016006820180546118b6906145cd565b80601f01602080910402602001604051908101604052809291908181526020018280546118e2906145cd565b801561192f5780601f106119045761010080835404028352916020019161192f565b820191906000526020600020905b81548152906001019060200180831161191257829003601f168201915b50505050508152505091506000600b81111561194d5761194d6143b6565b8260e00151600b811115611963576119636143b6565b141561199b576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50919050565b60025473ffffffffffffffffffffffffffffffffffffffff1633146119f2576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119fa6139e2565b565b60026000541415611a4f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260005560015474010000000000000000000000000000000000000000900460ff1615611abf5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b84611af6576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83611b2d576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316611b7a576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8216611bb7576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428263ffffffff1610611bf6576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051611c2e576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025473ffffffffffffffffffffffffffffffffffffffff16611c7d576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008581526004602052604090205460ff1615611cc6576040517f2ae8a9f800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020820120600080828152600760205260409020600501547801000000000000000000000000000000000000000000000000900460ff16600b811115611d1057611d106143b6565b14611d47576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600254604080517f863a43d5000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163863a43d59160048083019260209291908290030181865afa158015611db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ddb91906149ad565b6040517fc46060d40000000000000000000000000000000000000000000000000000000081526004810189905290915060009073ffffffffffffffffffffffffffffffffffffffff83169063c46060d490602401602060405180830381865afa158015611e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7091906149ad565b90503373ffffffffffffffffffffffffffffffffffffffff821614611ec1576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fcaef4f1b00000000000000000000000000000000000000000000000000000000815260048101899052600090819073ffffffffffffffffffffffffffffffffffffffff85169063caef4f1b906024016040805180830381865afa158015611f30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5491906149ca565b915091506000818311611f675781611f69565b825b9050828a11818b1115611fa8576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600860008154611fb99061492e565b91905081905590506001600460008f815260200190815260200160002060006101000a81548160ff02191690831515021790555087600560008381526020019081526020016000208190555080600660008a8152602001908152602001600020819055506040518061012001604052804281526020014281526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018e81526020018d81526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b63ffffffff1681526020016001600b811115612098576120986143b6565b815260209081018b905260008a8152600782526040908190208351815591830151600183015582015160028201805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116179055606083015160038301556080830151600483015560a083015160058301805460c086015163ffffffff1674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090911692909316919091179190911780825560e084015191907fffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000083600b8111156121cf576121cf6143b6565b021790555061010082015180516121f0916006840191602090910190613fd5565b505060408051838152602081018f905273ffffffffffffffffffffffffffffffffffffffff8e1681830152841515606082015290518f92507fa9554fcda31212dfb9fc1180820bd0bffc960baad3d9d1daa6c361ccfa8477be9181900360800190a2807f2d8b91cd39b91d452a6c29034de86e9ac2ff4936f8fe3a2aa319a662f4206ece600060016040516122869291906149ee565b60405180910390a2505060016000555050505050505050505050565b601381815481106122b257600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60015474010000000000000000000000000000000000000000900460ff16156123445760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b60035473ffffffffffffffffffffffffffffffffffffffff163314612395576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260005414156123e85760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260009081558181526005602052604090205480612433576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600861244082600a6134ca565b600b811115612451576124516143b6565b14612488576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a6124958260006134ca565b600b8111156124a6576124a66143b6565b146124dd576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518281527f1d5afae6999ee19e72635fe41333d99c8dc5dd052e08fcc93058b0706364421d90602001611486565b60015473ffffffffffffffffffffffffffffffffffffffff1633146125745760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b6119fa6000613ac1565b60015474010000000000000000000000000000000000000000900460ff16156125e95760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b837f534845524c4f434b5f434c41494d0000000000000000000000000000000000008114612643576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ee3afe347d5c74317041e2618c49534daf887c2414612690576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251602080850191909120600081815260079092526040909120600181015442146126e7576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60046126f48360056134ca565b600b811115612705576127056143b6565b1461273c576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505081516009805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216179091556020840151600a8054918416919092161790556040830151600b80546060860151151574010000000000000000000000000000000000000000027fffffffffffffffffffffff0000000000000000000000000000000000000000009091169290931691909117919091179055506080810151600c5560a0810151600d5560c0810151600e5560e0810151600f556101008101516010556101208101516011556101400151601255505050565b60015474010000000000000000000000000000000000000000900460ff161561289b5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b816128d2576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80612909576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600254604080517f863a43d5000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163863a43d59160048083019260209291908290030181865afa158015612979573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299d91906149ad565b6040517fc46060d40000000000000000000000000000000000000000000000000000000081526004810185905290915060009073ffffffffffffffffffffffffffffffffffffffff83169063c46060d490602401602060405180830381865afa158015612a0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a3291906149ad565b90503373ffffffffffffffffffffffffffffffffffffffff821614612a83576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205480612ac9576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260076020526040902060038101548614612b14576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612b2183600b6134ca565b9050612b2c81613b38565b612b62576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b6111578460006134ca565b837f534845524c4f434b5f434c41494d0000000000000000000000000000000000008114612bc9576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ee3afe347d5c74317041e2618c49534daf887c2414612c16576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026000541415612c695760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b6002600090815583516020808601919091208083526007909152604090912060a0840151600482015481148015612cf4576007612ca78560086134ca565b600b811115612cb857612cb86143b6565b14612cef576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fd1565b6007612d018560096134ca565b600b811115612d1257612d126143b6565b14612d49576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009612d568560006134ca565b600b811115612d6757612d676143b6565b14610fd1576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025473ffffffffffffffffffffffffffffffffffffffff163314612def576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119fa613b86565b60015474010000000000000000000000000000000000000000900460ff1615612e625760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004fcf6aa323a92eb92a58025e821f393da6c41bd61614612ed1576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026000541415612f245760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b600260009081558181526005602052604090205480612f6f576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001612f7c8260026134ca565b600b811115612f8d57612f8d6143b6565b14612fc4576040517fbaf3f0f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50506001600055565b73ffffffffffffffffffffffffffffffffffffffff811661301a576040517fb7852ebb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46617a6914158015613040575033731c11be636415973520dddf1b03822b4e2930d94a14155b15613077576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025473ffffffffffffffffffffffffffffffffffffffff16156130c7576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527ff200116515c6d70d53a45299bb7eba08ef985ec08bfe0baf31ad73907308a3189060200160405180910390a150565b60015474010000000000000000000000000000000000000000900460ff16156131ab5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004fcf6aa323a92eb92a58025e821f393da6c41bd6161461321a576040517fddb5de5e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600054141561326d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610515565b6002600090815581815260056020526040902054806132b8576040517fa9cb9e0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001612f7c8260036134ca565b60015473ffffffffffffffffffffffffffffffffffffffff16331461332c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b60035473ffffffffffffffffffffffffffffffffffffffff1661337b576040517f3af36e0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040517f36a0933bcc1c8c7ed7e8978ca49d792479a0262a8411115d4c90a07a784cf7cd90600090a1565b60015473ffffffffffffffffffffffffffffffffffffffff1633146134355760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610515565b73ffffffffffffffffffffffffffffffffffffffff81166134be5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610515565b6134c781613ac1565b50565b60008281526007602090815260408083206005810154600690935292819020549051780100000000000000000000000000000000000000000000000090920460ff1692917f2d8b91cd39b91d452a6c29034de86e9ac2ff4936f8fe3a2aa319a662f4206ece9061353d90859087906149ee565b60405180910390a2600083600b811115613559576135596143b6565b141561356d5761356884613c58565b6135ec565b600084815260076020526040902060050180548491907fffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000083600b8111156135d1576135d16143b6565b02179055506000848152600760205260409020426001909101555b5092915050565b6000600383600b811115613609576136096143b6565b148015613622575061361e6224ea0083614a09565b4211155b1561362f5750600161368d565b600061363e62093a8084614a09565b9050600184600b811115613654576136546143b6565b14801561366057504281105b801561367857506136746224ea0082614a09565b4211155b1561368757600191505061368d565b60009150505b92915050565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261376f9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613d45565b50505050565b80158061381557506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156137ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138139190614766565b155b6138875760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610515565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526138dd9084907f095ea7b300000000000000000000000000000000000000000000000000000000906064016136ed565b505050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526138dd9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016136ed565b6000600283600b81111561394e5761394e6143b6565b141561395c5750600161368d565b60035473ffffffffffffffffffffffffffffffffffffffff166139a057600883600b81111561398d5761398d6143b6565b141561399b5750600161368d565b6139d9565b600883600b8111156139b4576139b46143b6565b1480156139cc5750426139ca6201518084614a09565b105b156139d95750600161368d565b50600092915050565b60015474010000000000000000000000000000000000000000900460ff16613a4c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610515565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000600382600b811115613b4e57613b4e6143b6565b1415613b5c57506001919050565b600182600b811115613b7057613b706143b6565b1415613b7e57506001919050565b506000919050565b60015474010000000000000000000000000000000000000000900460ff1615613bf15760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610515565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613a973390565b60008181526007602081815260408084206003810180548652600480855292862080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905586865293909252838255600182018490556002820180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055918390559081018290556005810180547fffffffffffffff0000000000000000000000000000000000000000000000000016905590613d1c6006830182614059565b505060008181526006602081815260408084208054855260058352908420849055938352529055565b6000613da7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613e379092919063ffffffff16565b8051909150156138dd5780806020019051810190613dc59190614a21565b6138dd5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610515565b6060613e468484600085613e50565b90505b9392505050565b606082471015613ec85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610515565b843b613f165760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610515565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051613f3f9190614a3e565b60006040518083038185875af1925050503d8060008114613f7c576040519150601f19603f3d011682016040523d82523d6000602084013e613f81565b606091505b5091509150613f91828286613f9c565b979650505050505050565b60608315613fab575081613e49565b825115613fbb5782518084602001fd5b8160405162461bcd60e51b81526004016105159190614a5a565b828054613fe1906145cd565b90600052602060002090601f0160209004810192826140035760008555614049565b82601f1061401c57805160ff1916838001178555614049565b82800160010185558215614049579182015b8281111561404957825182559160200191906001019061402e565b5061405592915061408f565b5090565b508054614065906145cd565b6000825580601f10614075575050565b601f0160209004906000526020600020908101906134c791905b5b808211156140555760008155600101614090565b600080604083850312156140b757600080fd5b50508035926020909101359150565b6000602082840312156140d857600080fd5b5035919050565b803563ffffffff811681146140f357600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff8111828210171561414b5761414b6140f8565b60405290565b600082601f83011261416257600080fd5b813567ffffffffffffffff8082111561417d5761417d6140f8565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156141c3576141c36140f8565b816040528381528660208588010111156141dc57600080fd5b836020870160208301376000602085830101528094505050505092915050565b73ffffffffffffffffffffffffffffffffffffffff811681146134c757600080fd5b80356140f3816141fc565b80151581146134c757600080fd5b80356140f381614229565b6000806000808486036101c081121561425a57600080fd5b8535945061426a602087016140df565b9350604086013567ffffffffffffffff81111561428657600080fd5b61429288828901614151565b935050610160807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0830112156142c757600080fd5b6142cf614127565b91506142dd6060880161421e565b82526142eb6080880161421e565b60208301526142fc60a0880161421e565b604083015261430d60c08801614237565b606083015260e087013560808301526101008088013560a08401526101208089013560c0850152610140808a013560e0860152838a0135838601526101808a0135828601526101a08a013581860152505050508091505092959194509250565b6000806040838503121561438057600080fd5b823561438b816141fc565b946020939093013593505050565b6000602082840312156143ab57600080fd5b8135613e49816141fc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600c811061441c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60005b8381101561443b578181015183820152602001614423565b8381111561376f5750506000910152565b60008151808452614464816020860160208601614420565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081528151602082015260208201516040820152600060408301516144d4606084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608301516080830152608083015160a083015260a083015161451060c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015163ffffffff811660e08401525060e0830151610100614537818501836143e5565b84015161012084810152905061455161014084018261444c565b949350505050565b600080600080600060a0868803121561457157600080fd5b8535945060208601359350604086013561458a816141fc565b9250614598606087016140df565b9150608086013567ffffffffffffffff8111156145b457600080fd5b6145c088828901614151565b9150509295509295909350565b600181811c908216806145e157607f821691505b6020821081141561199b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8054600090600181811c908083168061463557607f831692505b6020808410821415614670577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8388526020880182801561468b57600181146146ba576146e5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008716825282820197506146e5565b60008981526020902060005b878110156146df578154848201529086019084016146c6565b83019850505b5050505050505092915050565b60006101208b835263ffffffff8b1660208401528060408401526147188184018b61461b565b73ffffffffffffffffffffffffffffffffffffffff998a1660608501526080840198909852505060a081019490945260c084019290925290931660e082015261010001919091529392505050565b60006020828403121561477857600080fd5b5051919050565b600061020088835263ffffffff881660208401528060408401526147a58184018861461b565b9150506147e7606083016147cd875473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff169052565b600185015473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff8116608084015250600285015473ffffffffffffffffffffffffffffffffffffffff811660a084015261485460c0840160ff8360a01c1615159052565b50600385015460e0830152600485015461010083015260058501546101208301526006850154610140830152600785015461016083015260088501546101808301526009909401546101a082015273ffffffffffffffffffffffffffffffffffffffff9283166101c082015291166101e0909101529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415614960576149606148ff565b5060010190565b600082821015614979576149796148ff565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000602082840312156149bf57600080fd5b8151613e49816141fc565b600080604083850312156149dd57600080fd5b505080516020909101519092909150565b604081016149fc82856143e5565b613e4960208301846143e5565b60008219821115614a1c57614a1c6148ff565b500190565b600060208284031215614a3357600080fd5b8151613e4981614229565b60008251614a50818460208701614420565b9190910192915050565b602081526000613e49602083018461444c56fea2646970667358221220c74c1b742575f5b0b7e63fae01462ba1ef7765d74e92a33ecd6b80acce5d9cbc64736f6c634300080a0033

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

0000000000000000000000008fcc879036fc8e45395ade7d4ef739200037695c0000000000000000000000004fcf6aa323a92eb92a58025e821f393da6c41bd6

-----Decoded View---------------
Arg [0] : _umaho (address): 0x8fCC879036Fc8e45395AdE7D4eF739200037695c
Arg [1] : _spcc (address): 0x4Fcf6AA323a92EB92a58025E821f393da6C41bD6

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000008fcc879036fc8e45395ade7d4ef739200037695c
Arg [1] : 0000000000000000000000004fcf6aa323a92eb92a58025e821f393da6c41bd6


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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