Contract

0xC9d5917A0cb82450Cd687AF31eCAaC967D7F121C

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PawnShop

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 50 runs

Other Settings:
istanbul EvmVersion, BSL 1.1 license
File 1 of 11 : PawnShop.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

// use copies of openzeppelin contracts with changed names for avoid dependency issues
import "../interfaces/IERC20.sol";
import "../interfaces/IERC721.sol";
import "../interfaces/IPawnShop.sol";
import "../lib/AppLib.sol";
import "../openzeppelin/ERC721Holder.sol";
import "../openzeppelin/ReentrancyGuard.sol";
import "../relay/ERC2771Context.sol";

interface IDelegation {
  function clearDelegate(bytes32 _id) external;
  function setDelegate(bytes32 _id, address _delegate) external;
}

/// @title PawnShop.sol contract provides a useful and flexible solution for borrowing
///        and lending assets with a unique feature of supporting both ERC721 and ERC20 tokens as collateral.
///        The contract's modular design allows for easy customization of fees, waiting periods,
///        and other parameters, providing a solid foundation for a decentralized borrowing and lending platform.
/// @author belbix
contract PawnShop is ERC721Holder, ReentrancyGuard, IPawnShop, ERC2771Context {

  //region ------------------------ Constants

  /// @notice Version of the contract
  /// @dev Should be incremented when contract changed
  string public constant VERSION = "1.0.10";
  /// @dev Time lock for any governance actions
  uint constant public TIME_LOCK = 2 days;
  /// @dev Denominator for any internal computation with low precision
  uint constant public DENOMINATOR = 10000;
  /// @dev Governance can't set fee more than this value
  uint constant public PLATFORM_FEE_MAX = 1000; // 10%
  /// @dev Standard auction duration that refresh when a new bid placed
  uint constant public AUCTION_DURATION = 1 days;
  /// @dev Timestamp date when contract created
  uint public immutable createdTs;
  /// @dev Block number when contract created
  uint public immutable createdBlock;
  //endregion ------------------------ Constants

  //region ------------------------ Changeable variables

  /// @dev Contract owner. Should be a multi-signature wallet.
  address public owner;
  /// @dev Fee recipient. Assume it will be a place with ability to manage different tokens
  address public feeRecipient;
  /// @dev 10% by default, percent of acquired tokens that will be used for buybacks
  uint public platformFee = 1000;
  /// @dev Amount of tokens for open position. Protection against spam
  uint public positionDepositAmount;
  /// @dev Token for antispam protection. Zero address means no protection
  address public positionDepositToken;
  /// @dev Time-locks for governance actions
  mapping(GovernanceAction => TimeLock) public timeLocks;
  //endregion ------------------------ Changeable variables

  //region ------------------------ Positions

  /// @inheritdoc IPawnShop
  uint public override positionCounter = 1;
  /// @dev PosId => Position. Hold all positions. Any record should not be removed
  mapping(uint => Position) public positions;
  /// @inheritdoc IPawnShop
  uint[] public override openPositions;
  /// @inheritdoc IPawnShop
  mapping(address => uint[]) public override positionsByCollateral;
  /// @inheritdoc IPawnShop
  mapping(address => uint[]) public override positionsByAcquired;
  /// @inheritdoc IPawnShop
  mapping(address => uint[]) public override borrowerPositions;
  /// @inheritdoc IPawnShop
  mapping(address => uint[]) public override lenderPositions;
  /// @inheritdoc IPawnShop
  mapping(IndexType => mapping(uint => uint)) public override posIndexes;
  //endregion ------------------------ Positions

  //region ------------------------ Auction

  /// @inheritdoc IPawnShop
  uint public override auctionBidCounter = 1;
  /// @dev BidId => Bid. Hold all bids. Any record should not be removed
  mapping(uint => AuctionBid) public auctionBids;
  /// @inheritdoc IPawnShop
  mapping(address => mapping(uint => uint)) public override lenderOpenBids;
  /// @inheritdoc IPawnShop
  mapping(uint => uint[]) public override positionToBidIds;
  /// @inheritdoc IPawnShop
  mapping(uint => uint) public override lastAuctionBidTs;
  //endregion ------------------------ Auction

  //region ------------------------ Constructor

  constructor(
    address _owner,
    address _depositToken,
    uint _positionDepositAmount,
    address _feeRecipient
  ) {
    if (_owner == address(0)) revert IAppErrors.PawnShopZeroOwner();
    if (_feeRecipient == address(0)) revert IAppErrors.PawnShopZeroFeeRecipient();
    owner = _owner;
    feeRecipient = _feeRecipient;
    positionDepositToken = _depositToken;
    createdTs = block.timestamp;
    createdBlock = block.number;
    positionDepositAmount = _positionDepositAmount;
  }
  //endregion ------------------------ Constructor

  //region ------------------------ Restrictions
  modifier onlyOwner() {
    if (_msgSender() != owner) revert IAppErrors.PawnShopNotOwner();
    _;
  }

  /// @dev Check time lock for governance actions and revert if conditions wrong
  modifier checkTimeLock(GovernanceAction action, address _address, uint _uint){
    TimeLock memory timeLock = timeLocks[action];
    if (timeLock.time == 0 || timeLock.time >= block.timestamp) revert IAppErrors.PawnShopTimeLock();
    if (_address != address(0)) {
      if (timeLock.addressValue != _address) revert IAppErrors.PawnShopWrongAddressValue();
    }
    if (_uint != 0) {
      if (timeLock.uintValue != _uint) revert IAppErrors.PawnShopWrongUintValue();
    }
    _;
    delete timeLocks[action];
  }
  //endregion ------------------------ Restrictions

  //region ------------------------ User actions

  /// @inheritdoc IPawnShop
  function openPosition(
    address _collateralToken,
    uint _collateralAmount,
    uint _collateralTokenId,
    address _acquiredToken,
    uint _acquiredAmount,
    uint _posDurationBlocks,
    uint _posFee,
    uint minAuctionAmount
  ) external nonReentrant override returns (uint){
    if (_posFee > DENOMINATOR * 10) revert IAppErrors.PawnShopPosFeeAbsurdlyHigh();
    if (_posDurationBlocks == 0 && _posFee != 0) revert IAppErrors.PawnShopPosFeeForInstantDealForbidden();
    if (_collateralAmount == 0 && _collateralTokenId == 0) revert IAppErrors.PawnShopWrongAmounts();
    if (_collateralToken == address(0)) revert IAppErrors.PawnShopZeroCToken();
    if (_acquiredToken == address(0)) revert IAppErrors.PawnShopZeroAToken();

    AssetType assetType = _getAssetType(_collateralToken);
    if (
      (!(assetType == AssetType.ERC20 && _collateralAmount != 0 && _collateralTokenId == 0))
      && (!(assetType == AssetType.ERC721 && _collateralAmount == 0 && _collateralTokenId != 0))
    ) revert IAppErrors.PawnShopIncorrect();

    Position memory pos;
    {
      PositionInfo memory info = PositionInfo(
        _posDurationBlocks,
        _posFee,
        block.number,
        block.timestamp
      );

      PositionCollateral memory collateral = PositionCollateral(
        _collateralToken,
        assetType,
        _collateralAmount,
        _collateralTokenId
      );

      PositionAcquired memory acquired = PositionAcquired(
        _acquiredToken,
        _acquiredAmount
      );

      PositionExecution memory execution = PositionExecution(
        address(0),
        0,
        0,
        0
      );

      pos = Position(
        positionCounter, // id
        _msgSender(), // borrower
        positionDepositToken,
        positionDepositAmount,
        true, // open
        minAuctionAmount,
        info,
        collateral,
        acquired,
        execution
      );
    }

    openPositions.push(pos.id);
    posIndexes[IndexType.LIST][pos.id] = openPositions.length - 1;

    positionsByCollateral[_collateralToken].push(pos.id);
    posIndexes[IndexType.BY_COLLATERAL][pos.id] = positionsByCollateral[_collateralToken].length - 1;

    positionsByAcquired[_acquiredToken].push(pos.id);
    posIndexes[IndexType.BY_ACQUIRED][pos.id] = positionsByAcquired[_acquiredToken].length - 1;

    borrowerPositions[_msgSender()].push(pos.id);
    posIndexes[IndexType.BORROWER_POSITION][pos.id] = borrowerPositions[_msgSender()].length - 1;

    positions[pos.id] = pos;
    positionCounter++;

    _takeDeposit(pos.id);
    _transferCollateral(pos.collateral, _msgSender(), address(this));
    emit PositionOpened(
      _msgSender(),
      pos.id,
      _collateralToken,
      _collateralAmount,
      _collateralTokenId,
      _acquiredToken,
      _acquiredAmount,
      _posDurationBlocks,
      _posFee
    );
    return pos.id;
  }

  /// @inheritdoc IPawnShop
  function closePosition(uint id) external nonReentrant override {
    Position storage pos = positions[id];
    if (pos.id != id) revert IAppErrors.PawnShopWrongId();
    if (pos.borrower != _msgSender()) revert IAppErrors.PawnShopNotBorrower();
    if (pos.execution.lender != address(0)) revert IAppErrors.PawnShopPositionExecuted();
    if (!pos.open) revert IAppErrors.PawnShopPositionClosed();

    _removePosFromIndexes(pos);
    removeIndexed(borrowerPositions[pos.borrower], posIndexes[IndexType.BORROWER_POSITION], pos.id);

    _transferCollateral(pos.collateral, address(this), pos.borrower);
    _returnDeposit(id);
    pos.open = false;
    emit PositionClosed(_msgSender(), id);
  }

  /// @inheritdoc IPawnShop
  function bid(uint id, uint amount) external nonReentrant override {
    Position storage pos = positions[id];
    if (pos.id != id) revert IAppErrors.PawnShopWrongId();
    if (!pos.open) revert IAppErrors.PawnShopPositionClosed();
    if (pos.execution.lender != address(0)) revert IAppErrors.PawnShopPositionExecuted();
    if (pos.acquired.acquiredAmount != 0) {
      if (amount != pos.acquired.acquiredAmount) revert IAppErrors.PawnShopWrongBidAmount();
      _executeBid(pos, 0, amount, _msgSender(), _msgSender());
    } else {
      _auctionBid(pos, amount, _msgSender());
    }
  }

  /// @inheritdoc IPawnShop
  function claim(uint id) external nonReentrant override {
    Position storage pos = positions[id];
    if (pos.id != id) revert IAppErrors.PawnShopWrongId();
    if (pos.execution.lender != _msgSender()) revert IAppErrors.PawnShopNotLender();
    uint posEnd = pos.execution.posStartBlock + pos.info.posDurationBlocks;
    if (posEnd >= block.number) revert IAppErrors.PawnShopTooEarlyToClaim();
    if (!pos.open) revert IAppErrors.PawnShopPositionClosed();

    _endPosition(pos);
    _transferCollateral(pos.collateral, address(this), _msgSender());
    _returnDeposit(id);
    emit PositionClaimed(_msgSender(), id);
  }

  /// @inheritdoc IPawnShop
  function redeem(uint id) external nonReentrant override {
    Position storage pos = positions[id];
    if (pos.id != id) revert IAppErrors.PawnShopWrongId();
    if (pos.borrower != _msgSender()) revert IAppErrors.PawnShopNotBorrower();
    if (pos.execution.lender == address(0)) revert IAppErrors.PawnShopPositionNotExecuted();
    if (!pos.open) revert IAppErrors.PawnShopPositionClosed();

    _endPosition(pos);
    uint toSend = _toRedeem(id);
    IERC20(pos.acquired.acquiredToken).transferFrom(_msgSender(), pos.execution.lender, toSend);
    _transferCollateral(pos.collateral, address(this), _msgSender());
    _returnDeposit(id);
    emit PositionRedeemed(_msgSender(), id);
  }

  /// @inheritdoc IPawnShop
  function acceptAuctionBid(uint posId) external nonReentrant override {
    if (lastAuctionBidTs[posId] + AUCTION_DURATION >= block.timestamp) revert IAppErrors.PawnShopAuctionNotEnded();
    if (positionToBidIds[posId].length == 0) revert IAppErrors.PawnShopNoBids();
    uint bidId = positionToBidIds[posId][positionToBidIds[posId].length - 1];

    AuctionBid storage _bid = auctionBids[bidId];
    if (_bid.id == 0) revert IAppErrors.PawnShopAuctionBidNotFound();
    if (!_bid.open) revert IAppErrors.PawnShopBidClosed();
    if (_bid.posId != posId) revert IAppErrors.PawnShopWrongBid();

    Position storage pos = positions[posId];
    if (pos.borrower != _msgSender()) revert IAppErrors.PawnShopNotBorrower();
    if (!pos.open) revert IAppErrors.PawnShopPositionClosed();

    pos.acquired.acquiredAmount = _bid.amount;
    _executeBid(pos, bidId, _bid.amount, address(this), _bid.lender);
    lenderOpenBids[_bid.lender][pos.id] = 0;
    _bid.open = false;
    emit AuctionBidAccepted(_msgSender(), posId, _bid.id);
  }

  /// @inheritdoc IPawnShop
  function closeAuctionBid(uint bidId) external nonReentrant override {
    AuctionBid storage _bid = auctionBids[bidId];
    address lender = _bid.lender;

    if (_bid.id == 0) revert IAppErrors.PawnShopBidNotFound();
    if (!_bid.open) revert IAppErrors.PawnShopBidClosed();
    if (lender != _msgSender()) revert IAppErrors.PawnShopNotLender();
    Position storage pos = positions[_bid.posId];

    uint _lastAuctionBidTs = lastAuctionBidTs[pos.id];
    bool isAuctionEnded = _lastAuctionBidTs + AUCTION_DURATION < block.timestamp;
    // in case if auction is not accepted during 2 weeks lender can close the bid
    bool isAuctionOverdue = _lastAuctionBidTs + AUCTION_DURATION + 2 weeks < block.timestamp;
    bool isLastBid = false;
    if (positionToBidIds[pos.id].length != 0) {
      uint lastBidId = positionToBidIds[pos.id][positionToBidIds[pos.id].length - 1];
      isLastBid = lastBidId == bidId;
    }
    if (!((isLastBid && isAuctionEnded) || !isLastBid || !pos.open || isAuctionOverdue)) revert IAppErrors.PawnShopAuctionNotEnded();

    lenderOpenBids[lender][pos.id] = 0;
    _bid.open = false;
    IERC20(pos.acquired.acquiredToken).transfer(lender, _bid.amount);
    emit AuctionBidClosed(pos.id, bidId);
  }
  //endregion ------------------------ User actions

  //region ------------------------ Internal functions

  /// @dev Transfer to this contract a deposit
  function _takeDeposit(uint posId) internal {
    Position storage pos = positions[posId];
    if (pos.depositToken != address(0)) {
      IERC20(pos.depositToken).transferFrom(pos.borrower, address(this), pos.depositAmount);
    }
  }

  /// @dev Return to borrower a deposit
  function _returnDeposit(uint posId) internal {
    Position storage pos = positions[posId];
    if (pos.depositToken != address(0)) {
      IERC20(pos.depositToken).transfer(pos.borrower, pos.depositAmount);
    }
  }

  /// @dev Execute bid for the open position
  ///      Transfer acquired tokens to borrower
  ///      In case of instant deal transfer collateral to lender
  function _executeBid(
    Position storage pos,
    uint bidId,
    uint amount,
    address acquiredMoneyHolder,
    address lender
  ) internal {
    uint feeAmount = amount * platformFee / DENOMINATOR;
    uint toSend = amount - feeAmount;
    if (acquiredMoneyHolder == address(this)) {
      IERC20(pos.acquired.acquiredToken).transfer(pos.borrower, toSend);
    } else {
      IERC20(pos.acquired.acquiredToken).transferFrom(acquiredMoneyHolder, pos.borrower, toSend);
      IERC20(pos.acquired.acquiredToken).transferFrom(acquiredMoneyHolder, address(this), feeAmount);
    }
    _transferFee(pos.acquired.acquiredToken, feeAmount);

    pos.execution.lender = lender;
    pos.execution.posStartBlock = block.number;
    pos.execution.posStartTs = block.timestamp;
    _removePosFromIndexes(pos);

    lenderPositions[lender].push(pos.id);
    posIndexes[IndexType.LENDER_POSITION][pos.id] = lenderPositions[lender].length - 1;

    // instant buy
    if (pos.info.posDurationBlocks == 0) {
      _transferCollateral(pos.collateral, address(this), lender);
      _returnDeposit(pos.id); // fix for SCB-1029
      _endPosition(pos);
    }
    emit BidExecuted(pos.id, bidId, amount, acquiredMoneyHolder, lender);
  }

  /// @dev Open an auction bid
  ///      Transfer acquired token to this contract
  function _auctionBid(Position storage pos, uint amount, address lender) internal {
    if (lenderOpenBids[lender][pos.id] != 0) revert IAppErrors.PawnShopBidAlreadyExists();
    if (amount < pos.minAuctionAmount) revert IAppErrors.PawnShopTooLowBid();

    if (positionToBidIds[pos.id].length != 0) {
      // if we have bids need to check auction duration
      if (lastAuctionBidTs[pos.id] + AUCTION_DURATION <= block.timestamp) revert IAppErrors.PawnShopAuctionEnded();

      uint lastBidId = positionToBidIds[pos.id][positionToBidIds[pos.id].length - 1];
      AuctionBid storage lastBid = auctionBids[lastBidId];
      if (lastBid.amount * 110 / 100 >= amount) revert IAppErrors.PawnShopNewBidTooLow();
    }

    AuctionBid memory _bid = AuctionBid(
      auctionBidCounter,
      pos.id,
      lender,
      amount,
      true
    );

    positionToBidIds[pos.id].push(_bid.id);
    // write index + 1 for keep zero as empty value
    lenderOpenBids[lender][pos.id] = positionToBidIds[pos.id].length;

    IERC20(pos.acquired.acquiredToken).transferFrom(_msgSender(), address(this), amount);

    lastAuctionBidTs[pos.id] = block.timestamp;
    auctionBids[_bid.id] = _bid;
    auctionBidCounter++;
    emit AuctionBidOpened(pos.id, _bid.id, amount, lender);
  }

  /// @dev Finalize position. Remove position from indexes
  function _endPosition(Position storage pos) internal {
    if (pos.execution.posEndTs != 0) revert IAppErrors.PawnShopAlreadyClaimed();
    pos.open = false;
    pos.execution.posEndTs = block.timestamp;
    removeIndexed(borrowerPositions[pos.borrower], posIndexes[IndexType.BORROWER_POSITION], pos.id);
    if (pos.execution.lender != address(0)) {
      removeIndexed(lenderPositions[pos.execution.lender], posIndexes[IndexType.LENDER_POSITION], pos.id);
    }

  }

  /// @dev Transfer collateral from sender to recipient
  function _transferCollateral(PositionCollateral memory _collateral, address _sender, address _recipient) internal {
    if (_collateral.collateralType == AssetType.ERC20) {
      if (_sender == address(this)) {
        IERC20(_collateral.collateralToken).transfer(_recipient, _collateral.collateralAmount);
      } else {
        IERC20(_collateral.collateralToken).transferFrom(_sender, _recipient, _collateral.collateralAmount);
      }
    } else if (_collateral.collateralType == AssetType.ERC721) {
      IERC721(_collateral.collateralToken).transferFrom(_sender, _recipient, _collateral.collateralTokenId);
    } else {
      revert("TPS: Wrong asset type");
    }
  }

  /// @dev Transfer fee to platform. Assume that token inside this contract
  ///      Do buyback if possible, otherwise just send to controller for manual handling
  function _transferFee(address token, uint amount) internal {
    // little deals can have zero fees
    if (amount == 0) {
      return;
    }
    IERC20(token).transfer(feeRecipient, amount);
  }

  /// @dev Remove position from common indexes
  function _removePosFromIndexes(Position memory _pos) internal {
    removeIndexed(openPositions, posIndexes[IndexType.LIST], _pos.id);
    removeIndexed(positionsByCollateral[_pos.collateral.collateralToken], posIndexes[IndexType.BY_COLLATERAL], _pos.id);
    removeIndexed(positionsByAcquired[_pos.acquired.acquiredToken], posIndexes[IndexType.BY_ACQUIRED], _pos.id);
  }
  //endregion ------------------------ Internal functions

  //region ------------------------ Views

  /// @inheritdoc IPawnShop
  function toRedeem(uint id) external view override returns (uint){
    return _toRedeem(id);
  }

  function _toRedeem(uint id) private view returns (uint){
    Position memory pos = positions[id];
    return pos.acquired.acquiredAmount +
    (pos.acquired.acquiredAmount * pos.info.posFee / DENOMINATOR);
  }

  /// @inheritdoc IPawnShop
  function getAssetType(address _token) external view override returns (AssetType){
    return _getAssetType(_token);
  }

  function _getAssetType(address _token) private view returns (AssetType){
    if (_isERC721(_token)) {
      return AssetType.ERC721;
    } else if (_isERC20(_token)) {
      return AssetType.ERC20;
    } else {
      revert("TPS: Unknown asset");
    }
  }

  /// @dev Return true if given token is ERC721 token
  function isERC721(address _token) external view override returns (bool) {
    return _isERC721(_token);
  }

  //noinspection NoReturn
  function _isERC721(address _token) private view returns (bool) {
    //slither-disable-next-line unused-return,variable-scope,uninitialized-local
    try IERC721(_token).supportsInterface{gas: 30000}(type(IERC721).interfaceId) returns (bool result){
      return result;
    } catch {
      return false;
    }
  }

  /// @dev Return true if given token is ERC20 token
  function isERC20(address _token) external view override returns (bool) {
    return _isERC20(_token);
  }

  //noinspection NoReturn
  function _isERC20(address _token) private view returns (bool) {
    //slither-disable-next-line unused-return,variable-scope,uninitialized-local
    try IERC20(_token).totalSupply{gas: 30000}() returns (uint){
      return true;
    } catch {
      return false;
    }
  }

  /// @inheritdoc IPawnShop
  function openPositionsSize() external view override returns (uint) {
    return openPositions.length;
  }

  /// @inheritdoc IPawnShop
  function auctionBidSize(uint posId) external view override returns (uint) {
    return positionToBidIds[posId].length;
  }

  function positionsByCollateralSize(address collateral) external view override returns (uint) {
    return positionsByCollateral[collateral].length;
  }

  function positionsByAcquiredSize(address acquiredToken) external view override returns (uint) {
    return positionsByAcquired[acquiredToken].length;
  }

  function borrowerPositionsSize(address borrower) external view override returns (uint) {
    return borrowerPositions[borrower].length;
  }

  function lenderPositionsSize(address lender) external view override returns (uint) {
    return lenderPositions[lender].length;
  }

  /// @inheritdoc IPawnShop
  function getPosition(uint posId) external view override returns (Position memory) {
    return positions[posId];
  }

  /// @inheritdoc IPawnShop
  function getAuctionBid(uint bidId) external view override returns (AuctionBid memory) {
    return auctionBids[bidId];
  }
  //endregion ------------------------ Views

  //region ------------------------ Governance actions

  /// @inheritdoc IPawnShop
  function announceGovernanceAction(
    GovernanceAction id,
    address addressValue,
    uint uintValue
  ) external onlyOwner override {
    if (timeLocks[id].time != 0) revert IAppErrors.PawnShopAlreadyAnnounced();
    timeLocks[id] = TimeLock(
      block.timestamp + TIME_LOCK,
      addressValue,
      uintValue
    );
    emit GovernanceActionAnnounced(uint(id), addressValue, uintValue);
  }

  /// @inheritdoc IPawnShop
  function setOwner(address _newOwner) external onlyOwner override
  checkTimeLock(GovernanceAction.ChangeOwner, _newOwner, 0) {
    if (_newOwner == address(0)) revert IAppErrors.PawnShopZeroAddress();
    emit OwnerChanged(owner, _newOwner);
    owner = _newOwner;
  }

  /// @inheritdoc IPawnShop
  function setFeeRecipient(address _newFeeRecipient) external onlyOwner override
  checkTimeLock(GovernanceAction.ChangeFeeRecipient, _newFeeRecipient, 0) {
    if (_newFeeRecipient == address(0)) revert IAppErrors.PawnShopZeroAddress();
    emit FeeRecipientChanged(feeRecipient, _newFeeRecipient);
    feeRecipient = _newFeeRecipient;
  }

  /// @inheritdoc IPawnShop
  function setPlatformFee(uint _value) external onlyOwner override
  checkTimeLock(GovernanceAction.ChangePlatformFee, address(0), _value) {
    if (_value > PLATFORM_FEE_MAX) revert IAppErrors.PawnShopTooHighValue();
    emit PlatformFeeChanged(platformFee, _value);
    platformFee = _value;
  }

  /// @inheritdoc IPawnShop
  function setPositionDepositAmount(uint _value) external onlyOwner override
  checkTimeLock(GovernanceAction.ChangePositionDepositAmount, address(0), _value) {
    emit DepositAmountChanged(positionDepositAmount, _value);
    positionDepositAmount = _value;
  }

  /// @inheritdoc IPawnShop
  function setPositionDepositToken(address _value) external onlyOwner override
  checkTimeLock(GovernanceAction.ChangePositionDepositToken, _value, 0) {
    emit DepositTokenChanged(positionDepositToken, _value);
    positionDepositToken = _value;
  }

  /// @dev Delegate snapshot votes to another address
  function delegateVotes(address _delegateContract,bytes32 _id, address _delegate) external onlyOwner {
    IDelegation(_delegateContract).setDelegate(_id, _delegate);
  }

  /// @dev Remove delegated votes.
  function clearDelegatedVotes(address _delegateContract, bytes32 _id) external onlyOwner {
    IDelegation(_delegateContract).clearDelegate(_id);
  }
  //endregion ------------------------ Governance actions

  //region ------------------------ ArrayLib
  /// @dev Remove from array the item with given id and move the last item on it place
  ///      Use with mapping for keeping indexes in correct ordering
  function removeIndexed(
    uint256[] storage array,
    mapping(uint256 => uint256) storage indexes,
    uint256 id
  ) internal {
    AppLib.removeIndexed(array, indexes, id);
  }
  //endregion ------------------------ ArrayLib
}

File 2 of 11 : IAppErrors.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @notice All errors of the app
interface IAppErrors {

  //region ERC20Errors
  /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
  error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

  /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
  error ERC20InvalidSender(address sender);

  /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
  error ERC20InvalidReceiver(address receiver);

  /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
  error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

  /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
  error ERC20InvalidApprover(address approver);

  /**
   * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
  error ERC20InvalidSpender(address spender);

  //endregion ERC20Errors

  //region ERC721Errors

  /**
  * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
  error ERC721InvalidOwner(address owner);

  /**
   * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
  error ERC721NonexistentToken(uint256 tokenId);

  /**
   * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
  error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

  /**
   * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
  error ERC721InvalidSender(address sender);

  /**
   * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
  error ERC721InvalidReceiver(address receiver);

  /**
   * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
  error ERC721InsufficientApproval(address operator, uint256 tokenId);

  /**
   * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
  error ERC721InvalidApprover(address approver);

  /**
   * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
  error ERC721InvalidOperator(address operator);

  //endregion ERC721Errors

  error ZeroAddress();
  error ZeroValueNotAllowed();
  error ZeroToken();
  error LengthsMismatch();
  error NotEnoughBalance();
  error NotEnoughAllowance();
  error EmptyNameNotAllowed();
  error NotInitialized();
  error AlreadyInitialized();
  error ReentrancyGuardReentrantCall();
  error TooLongString();
  error AlreadyDeployed(address deployed);

  //region Restrictions
  error ErrorNotDeployer(address sender);
  error ErrorNotGoc();
  error NotGovernance(address sender);
  error ErrorOnlyEoa();
  error NotEOA(address sender);
  error ErrorForbidden(address sender);
  error AdminOnly();
  error ErrorNotItemController(address sender);
  error ErrorNotHeroController(address sender);
  error ErrorNotDungeonFactory(address sender);
  error ErrorNotObjectController(address sender);
  error ErrorNotStoryController();
  error ErrorNotAllowedSender();
  error MintNotAllowed();
  //endregion Restrictions

  //region PackingLib
  error TooHighValue(uint value);
  error IntValueOutOfRange(int value);
  error OutOfBounds(uint index, uint length);
  error UnexpectedValue(uint expected, uint actual);
  error WrongValue(uint newValue, uint actual);
  error IntOutOfRange(int value);
  error ZeroValue();
  /// @notice packCustomDataChange requires an input string with two zero bytes at the beginning
  ///         0xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0000
  /// This error happens if these bytes are not zero
  error IncompatibleInputString();
  error IncorrectOtherItemTypeKind(uint8 kind);
  //endregion PackingLib

  //region Hero
  error ErrorHeroIsNotRegistered(address heroToken);
  error ErrorHeroIsDead(address heroToken, uint heroTokenId);
  error ErrorHeroNotInDungeon();
  error HeroInDungeon();
  error ErrorNotOwner(address token, uint tokenId);
  error Staked(address heroToken, uint heroId);
  error NameTaken();
  error TooBigName();
  error WrongSymbolsInTheName();
  error NoPayToken(address token, uint payTokenAmount);
  error AlreadyHaveReinforcement();
  /// @notice SIP-001 - Reinforcement requires 3 skills
  error ErrorReinforcementRequiresThreeSkills();
  error WrongTier(uint tier);
  error NotEnoughNgLevel(uint8 ngLevel);
  error NgpNotActive(address hero);
  error RebornNotAllowed();
  error AlreadyPrePaidHero();
  //endregion Hero

  //region Dungeon
  error ErrorDungeonIsFreeAlready();
  error ErrorNoEligibleDungeons();
  error ErrorDungeonBusy();
  error ErrorNoDungeonsForBiome(uint8 heroBiome);
  error ErrorDungeonCompleted();
  error ErrorAlreadyInDungeon();
  error NotEnoughTokens(uint balance, uint expectedBalance);
  error DungeonAlreadySpecific(uint16 dungNum);
  error DungeonAlreadySpecific2(uint16 dungNum);
  error WrongSpecificDungeon();
  //endregion Dungeon

  //region Items
  error ErrorItemNotEligibleForTheSlot(uint itemType, uint8 itemSlot);
  error ErrorItemSlotBusyHand(uint8 slot);
  error ErrorItemSlotBusy();
  error ErrorItemNotInSlot();
  error ErrorConsumableItemIsUsed(address item);
  error ErrorCannotRemoveItemFromMap();
  error ErrorCannotRemoveDataFromMap();
  error EquippedItemsExist();
  error ItemEquipped(address item, uint itemId);
  error ZeroItemMetaType();
  error NotZeroOtherItemMetaType();
  error ZeroLevel();
  error ItemTypeChanged();
  error ItemMetaTypeChanged();
  error UnknownItem(address item);
  error ErrorEquipForbidden();
  error EquipForbiddenInDungeon();
  error TakeOffForbiddenInDungeon();
  error Consumable(address item);
  error NotConsumable(address item);
  error Broken(address item);
  error ZeroLife();
  error RequirementsToItemAttributes();
  error NotEquipped(address item);
  error ZeroDurability();
  error ZeroAugmentation();
  error TooHighAgLevel(uint8 augmentationLevel);
  error UseForbiddenZeroPayToken();
  error IncorrectMinMaxAttributeRange(int32 min, int32 max);
  error SameIdsNotAllowed();
  error ZeroFragility();
  error OtherTypeItemNotRepairable();
  error NotOther();
  error DoubleItemUsageForbidden(uint itemIndex, address[] items);
  error ItemAlreadyUsedInSlot(address item, uint8 equippedSlot);
  error WrongWayToRegisterItem();
  error UnionItemNotFound(address item);
  error WrongListUnionItemTokens(address item, uint countTokens, uint requiredCountTokens);
  error UnknownUnionConfig(uint unionConfigId);
  error UserHasNoKeyPass(address user, address keyPassItem);
  error MaxValue(uint value);
  error UnexpectedOtherItem(address item);
  error NotExist();
  //endregion Items

  //region Stages
  error ErrorWrongStage(uint stage);
  error ErrorNotStages();
  //endregion Stages

  //region Level
  error ErrorWrongLevel(uint heroLevel);
  error ErrorLevelTooLow(uint heroLevel);
  error ErrorHeroLevelStartFrom1();
  error ErrorWrongLevelUpSum();
  error ErrorMaxLevel();
  //endregion Level

  //region Treasure
  error ErrorNotValidTreasureToken(address treasureToken);
  //endregion Treasure

  //region State
  error ErrorPaused();
  error ErrorNotReady();
  error ErrorNotObject1();
  error ErrorNotObject2();
  error ErrorNotCompleted();
  //endregion State

  //region Biome
  error ErrorNotBiome();
  error ErrorIncorrectBiome(uint biome);
  error TooHighBiome(uint biome);
  //endregion Biome

  //region Misc
  error ErrorWrongMultiplier(uint multiplier);
  error ErrorNotEnoughMana(uint32 mana, uint requiredMana);
  error ErrorExperienceMustNotDecrease();
  error ErrorNotEnoughExperience();
  error ErrorNotChances();
  error ErrorNotEligible(address heroToken, uint16 dungNum);
  error ErrorZeroKarmaNotAllowed();
  //endregion Misc

  //region GOC
  error GenObjectIdBiomeOverflow(uint8 biome);
  error GenObjectIdSubTypeOverflow(uint subType);
  error GenObjectIdIdOverflow(uint id);
  error UnknownObjectTypeGoc1(uint8 objectType);
  error UnknownObjectTypeGoc2(uint8 objectType);
  error UnknownObjectTypeGocLib1(uint8 objectType);
  error UnknownObjectTypeGocLib2(uint8 objectType);
  error UnknownObjectTypeForSubtype(uint8 objectSubType);
  error FightDelay();
  error ZeroChance();
  error TooHighChance(uint32 chance);
  error TooHighRandom(uint random);
  error EmptyObjects();
  error ObjectNotFound();
  error WrongGetObjectTypeInput();
  error WrongChances(uint32 chances, uint32 maxChances);
  //endregion GOC

  //region Story
  error PageNotRemovedError(uint pageId);
  error NotItem1();
  error NotItem2();
  error NotRandom(uint32 random);
  error NotHeroData();
  error NotGlobalData();
  error ZeroStoryIdRemoveStory();
  error ZeroStoryIdStoryAction();
  error ZeroStoryIdAction();
  error NotEnoughAmount(uint balance, uint requiredAmount);
  error NotAnswer();
  error AnswerStoryIdMismatch(uint16 storyId, uint16 storyIdFromAnswerHash);
  error AnswerPageIdMismatch(uint16 pageId, uint16 pageIdFromAnswerHash);
  //endregion Story

  //region FightLib
  error NotMagic();
  error NotAType(uint atype);
  //endregion FightLib

  //region MonsterLib
  error NotYourDebuffItem();
  error UnknownAttackType(uint attackType);
  error NotYourAttackItem();
  /// @notice The skill item cannot be used because it doesn't belong either to the hero or to the hero's helper
  error NotYourBuffItem();
  //endregion MonsterLib

  //region GameToken
  error ApproveToZeroAddress();
  error MintToZeroAddress();
  error TransferToZeroAddress();
  error TransferAmountExceedsBalance(uint balance, uint value);
  error InsufficientAllowance();
  error BurnAmountExceedsBalance();
  error NotMinter(address sender);
  //endregion GameToken

  //region NFT
  error TokenTransferNotAllowed();
  error IdOverflow(uint id);
  error NotExistToken(uint tokenId);
  error EquippedItemIsNotAllowedToTransfer(uint tokenId);
  //endregion NFT

  //region CalcLib
  error TooLowX(uint x);
  //endregion CalcLib

  //region Controller
  error NotFutureGovernance(address sender);
  //endregion Controller

  //region Oracle
  error OracleWrongInput();
  //endregion Oracle

  //region ReinforcementController
  error AlreadyStaked();
  error MaxFee(uint8 fee);
  error MinFee(uint8 fee);
  error StakeHeroNotStats();
  error NotStaked();
  error NoStakedHeroes();
  error GuildHelperNotAvailable(uint guildId, address helper, uint helperId);
  error HelperNotAvailableInGivenBiome();
  //endregion ReinforcementController

  //region SponsoredHero
  error InvalidHeroClass();
  error ZeroAmount();
  error InvalidProof();
  error NoHeroesAvailable();
  error AlreadyRegistered();
  //endregion SponsoredHero

  //region SacraRelay
  error SacraRelayNotOwner();
  error SacraRelayNotDelegator();
  error SacraRelayNotOperator();
  error SacraRelayInvalidChainId(uint callChainId, uint blockChainId);
  error SacraRelayInvalidNonce(uint callNonce, uint txNonce);
  error SacraRelayDeadline();
  error SacraRelayDelegationExpired();
  error SacraRelayNotAllowed();
  error SacraRelayInvalidSignature();
  /// @notice This error is generated when custom error is caught
  /// There is no info about custom error in SacraRelay
  /// but you can decode custom error by selector, see tests
  error SacraRelayNoErrorSelector(bytes4 selector, string tracingInfo);
  /// @notice This error is generated when custom error is caught
  /// There is no info about custom error in SacraRelay
  /// but you can decode custom error manually from {errorBytes} as following:
  /// if (keccak256(abi.encodeWithSignature("MyError()")) == keccak256(errorBytes)) { ... }
  error SacraRelayUnexpectedReturnData(bytes errorBytes, string tracingInfo);
  error SacraRelayCallToNotContract(address notContract, string tracingInfo);
  //endregion SacraRelay

  //region Misc
  error UnknownHeroClass(uint heroClass);
  error AbsDiff(int32 a, int32 b);
  //region Misc

  //region ------------------------ UserController
  error NoAvailableLootBox(address msgSender, uint lootBoxKind);
  error FameHallHeroAlreadyRegistered(uint8 openedNgLevel);

  //endregion ------------------------ UserController

  //region ------------------------ Guilds
  error AlreadyGuildMember();
  error NotGuildMember();
  error WrongGuild();
  error GuildActionForbidden(uint right);
  error GuildHasMaxSize(uint guildSize);
  error GuildHasMaxLevel(uint level);
  error TooLongUrl();
  error TooLongDescription();
  error CannotRemoveGuildOwnerFromNotEmptyGuild();
  error GuildControllerOnly();
  error GuildAlreadyHasShelter();
  error ShelterIsBusy();
  error ShelterIsNotRegistered();
  error ShelterIsNotOwnedByTheGuild();
  error ShelterIsInUse();
  error GuildHasNoShelter();
  error ShelterBidIsNotAllowedToBeUsed();
  error ShelterHasHeroesInside();
  error SecondGuildAdminIsNotAllowed();
  error NotEnoughGuildBankBalance(uint guildId);

  error GuildReinforcementCooldownPeriod();
  error NoStakedGuildHeroes();
  error NotStakedInGuild();
  error ShelterHasNotEnoughLevelForReinforcement();
  error NotBusyGuildHelper();

  error GuildRequestNotActive();
  error GuildRequestNotAvailable();
  error NotAdminCannotAddMemberWithNotZeroRights();
  //endregion ------------------------ Guilds

  //region ------------------------ Shelters
  error ErrorNotShelterController();
  error ErrorNotGuildController();
  error ShelterHasNotItem(uint shelterId, address item);
  error MaxNumberItemsSoldToday(uint numSoldItems, uint limit);
  error GuildHasNotEnoughPvpPoints(uint64 pointsAvailable, uint pointRequired);
  error FreeShelterItemsAreNotAllowed(uint shelterId, address item);
  error TooLowShelterLevel(uint8 shelterLevel, uint8 allowedShelterLevel);
  error NotEnoughPvpPointsCapacity(address user, uint usedPoints, uint pricePvpPoints, uint64 capactiy);
  error IncorrectShelterLevel(uint8 shelterLevel);
  //endregion ------------------------ Shelters

  //region ------------------------ Auction
  error WrongAuctionPosition();
  error AuctionPositionClosed();
  error AuctionBidOpened(uint positionId);
  error TooLowAmountToBid();
  error AuctionEnded();
  error TooLowAmountForNewBid();
  error AuctionSellerOnly();
  error AuctionBuyerOnly();
  error AuctionBidNotFound();
  error AuctionBidClosed();
  error OnlyShelterAuction();
  error CannotCloseLastBid();
  error AuctionNotEnded();
  error NotShelterAuction();
  error AuctionPositionOpened(uint positionId);
  error AuctionSellerCannotBid();
  error CannotApplyNotLastBid();
  error AuctionGuildWithShelterCannotBid();
  //endregion ------------------------ Auction

  //region ------------------------ Pawnshop
  error AuctionPositionNotSupported(uint positionId);
  error PositionNotSupported(uint positionId);
  error NotNftPositionNotSupported(uint positionId);
  error CallFailed(bytes callResultData);

  error PawnShopZeroOwner();
  error PawnShopZeroFeeRecipient();
  error PawnShopNotOwner();
  error PawnShopAlreadyAnnounced();
  error PawnShopTimeLock();
  error PawnShopWrongAddressValue();
  error PawnShopWrongUintValue();
  error PawnShopZeroAddress();
  error PawnShopTooHighValue();
  error PawnShopZeroAToken();
  error PawnShopZeroCToken();
  error PawnShopWrongAmounts();
  error PawnShopPosFeeForInstantDealForbidden();
  error PawnShopPosFeeAbsurdlyHigh();
  error PawnShopIncorrect();
  error PawnShopWrongId();
  error PawnShopNotBorrower();
  error PawnShopPositionClosed();
  error PawnShopPositionExecuted();
  error PawnShopWrongBidAmount();
  error PawnShopTooLowBid();
  error PawnShopNewBidTooLow();
  error PawnShopBidAlreadyExists();
  error PawnShopAuctionEnded();
  error PawnShopNotLender();
  error PawnShopTooEarlyToClaim();
  error PawnShopPositionNotExecuted();
  error PawnShopAlreadyClaimed();
  error PawnShopAuctionNotEnded();
  error PawnShopBidClosed();
  error PawnShopNoBids();
  error PawnShopAuctionBidNotFound();
  error PawnShopWrongBid();
  error PawnShopBidNotFound();

  //endregion ------------------------ Pawnshop
}

File 3 of 11 : IERC165.sol
// SPDX-License-Identifier: MIT

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 4 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT

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 5 of 11 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./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 6 of 11 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

File 7 of 11 : IPawnShop.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @title Interface for Tetu PawnShop contract
/// @author belbix
interface IPawnShop {

  event PositionOpened(
    address indexed sender,
    uint256 posId,
    address collateralToken,
    uint256 collateralAmount,
    uint256 collateralTokenId,
    address acquiredToken,
    uint256 acquiredAmount,
    uint256 posDurationBlocks,
    uint256 posFee
  );
  event PositionClosed(address indexed borrower, uint256 posId);
  event BidExecuted(
    uint256 posId,
    uint256 bidId,
    uint256 amount,
    address acquiredMoneyHolder,
    address lender
  );
  event AuctionBidOpened(uint256 posId, uint256 bidId, uint256 amount, address lender);
  event PositionClaimed(address indexed sender, uint256 posId);
  event PositionRedeemed(address indexed sender, uint256 posId);
  event AuctionBidAccepted(address indexed borrower, uint256 posId, uint256 bidId);
  event AuctionBidClosed(uint256 posId, uint256 bidId);

  event GovernanceActionAnnounced(uint256 id, address addressValue, uint256 uintValue);
  event OwnerChanged(address oldOwner, address newOwner);
  event FeeRecipientChanged(address oldRecipient, address newRecipient);
  event PlatformFeeChanged(uint256 oldFee, uint256 newFee);
  event DepositAmountChanged(uint256 oldAmount, uint256 newAmount);
  event DepositTokenChanged(address oldToken, address newToken);

  enum GovernanceAction {
    ChangeOwner, // 0
    ChangeFeeRecipient, // 1
    ChangePlatformFee, // 2
    ChangePositionDepositAmount, // 3
    ChangePositionDepositToken // 4
  }

  enum AssetType {
    ERC20, // 0
    ERC721 // 1
  }

  enum IndexType {
    LIST, // 0
    BY_COLLATERAL, // 1
    BY_ACQUIRED, // 2
    BORROWER_POSITION, // 3
    LENDER_POSITION // 4
  }

  struct TimeLock {
    uint256 time;
    address addressValue;
    uint256 uintValue;
  }

  struct Position {
    uint256 id;
    address borrower;
    address depositToken;
    uint256 depositAmount;
    bool open;
    uint minAuctionAmount;
    PositionInfo info;
    PositionCollateral collateral;
    PositionAcquired acquired;
    PositionExecution execution;
  }

  struct PositionInfo {
    uint256 posDurationBlocks;
    uint256 posFee;
    uint256 createdBlock;
    uint256 createdTs;
  }

  struct PositionCollateral {
    address collateralToken;
    AssetType collateralType;
    uint256 collateralAmount;
    uint256 collateralTokenId;
  }

  struct PositionAcquired {
    address acquiredToken;
    uint256 acquiredAmount;
  }

  struct PositionExecution {
    address lender;
    uint256 posStartBlock;
    uint256 posStartTs;
    uint256 posEndTs;
  }

  struct AuctionBid {
    uint256 id;
    uint256 posId;
    address lender;
    uint256 amount;
    bool open;
  }

  // ****************** VIEWS ****************************

  /// @dev PosId counter. Should start from 1 for keep 0 as empty value
  function positionCounter() external view returns (uint256);

  /// @notice Return Position for given id
  /// @dev AbiEncoder not able to auto generate functions for mapping with structs
  function getPosition(uint256 posId) external view returns (Position memory);

  /// @dev Hold open positions ids. Removed when position closed
  function openPositions(uint256 index) external view returns (uint256 posId);

  /// @dev Collateral token => PosIds
  function positionsByCollateral(address collateralToken, uint256 index) external view returns (uint256 posId);

  /// @dev Acquired token => PosIds
  function positionsByAcquired(address acquiredToken, uint256 index) external view returns (uint256 posId);

  /// @dev Borrower token => PosIds
  function borrowerPositions(address borrower, uint256 index) external view returns (uint256 posId);

  /// @dev Lender token => PosIds
  function lenderPositions(address lender, uint256 index) external view returns (uint256 posId);

  /// @dev index type => PosId => index
  ///      Hold array positions for given type of array
  function posIndexes(IndexType typeId, uint256 posId) external view returns (uint256 index);

  /// @dev BidId counter. Should start from 1 for keep 0 as empty value
  function auctionBidCounter() external view returns (uint256);

  /// @notice Return auction bid for given id
  /// @dev AbiEncoder not able to auto generate functions for mapping with structs
  function getAuctionBid(uint256 bidId) external view returns (AuctionBid memory);

  /// @dev lender => PosId => positionToBidIds + 1
  ///      Lender auction position for given PosId. 0 keep for empty position
  function lenderOpenBids(address lender, uint256 posId) external view returns (uint256 index);

  /// @dev PosId => bidIds. All open and close bids for the given position
  function positionToBidIds(uint256 posId, uint256 index) external view returns (uint256 bidId);

  /// @dev PosId => timestamp. Timestamp of the last bid for the auction
  function lastAuctionBidTs(uint256 posId) external view returns (uint256 ts);

  /// @dev Return amount required for redeem position
  function toRedeem(uint256 posId) external view returns (uint256 amount);

  /// @dev Return asset type ERC20 or ERC721
  function getAssetType(address _token) external view returns (AssetType);

  function isERC721(address _token) external view returns (bool);

  function isERC20(address _token) external view returns (bool);

  /// @dev Return size of active positions
  function openPositionsSize() external view returns (uint256);

  /// @dev Return size of all auction bids for given position
  function auctionBidSize(uint256 posId) external view returns (uint256);

  function positionsByCollateralSize(address collateral) external view returns (uint256);

  function positionsByAcquiredSize(address acquiredToken) external view returns (uint256);

  function borrowerPositionsSize(address borrower) external view returns (uint256);

  function lenderPositionsSize(address lender) external view returns (uint256);

  // ************* USER ACTIONS *************

  /// @dev Borrower action. Assume approve
  ///      Allows the user to create a new borrowing position by depositing their collateral tokens.
  function openPosition(
    address _collateralToken,
    uint256 _collateralAmount,
    uint256 _collateralTokenId,
    address _acquiredToken,
    uint256 _acquiredAmount,
    uint256 _posDurationBlocks,
    uint256 _posFee,
    uint minAuctionPrice
  ) external returns (uint256);

  /// @dev Borrower action
  ///      Close not executed position. Return collateral and deposit to borrower
  function closePosition(uint256 id) external;

  /// @dev Lender action. Assume approve for acquired token
  ///      Place a bid for given position ID
  ///      It can be an auction bid if acquired amount is zero
  function bid(uint256 id, uint256 amount) external;

  /// @dev Lender action
  ///      Transfer collateral to lender if borrower didn't return the loan
  ///      Deposit will be returned to borrower
  function claim(uint256 id) external;

  /// @dev Borrower action. Assume approve on acquired token
  ///      Return the loan to lender, transfer collateral and deposit to borrower
  function redeem(uint256 id) external;

  /// @dev Borrower action. Assume that auction ended.
  ///      Transfer acquired token to borrower
  function acceptAuctionBid(uint256 posId) external;

  /// @dev Lender action. Requires ended auction, or not the last bid
  ///      Close auction bid and transfer acquired tokens to lender
  function closeAuctionBid(uint256 bidId) external;

  /// @dev Announce governance action
  function announceGovernanceAction(GovernanceAction id, address addressValue, uint256 uintValue) external;

  /// @dev Set new contract owner
  function setOwner(address _newOwner) external;

  /// @dev Set new fee recipient
  function setFeeRecipient(address _newFeeRecipient) external;

  /// @dev Platform fee in range 0 - 500, with denominator 10000
  function setPlatformFee(uint256 _value) external;

  /// @dev Tokens amount that need to deposit for a new position
  ///      Will be returned when position closed
  function setPositionDepositAmount(uint256 _value) external;

  /// @dev Tokens that need to deposit for a new position
  function setPositionDepositToken(address _value) external;

  function platformFee() external view returns (uint);
  function positionDepositToken() external view returns (address);
  function AUCTION_DURATION() external view returns (uint);
  function positionDepositAmount() external view returns (uint);
}

File 8 of 11 : AppLib.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

import "../interfaces/IERC20.sol";

/// @notice Common internal utils
library AppLib {

  /// @notice Make infinite approve of {token} to {spender} if the approved amount is less than {amount}
  /// @dev Should NOT be used for third-party pools
  function approveIfNeeded(address token, uint amount, address spender) internal {
    if (IERC20(token).allowance(address(this), spender) < amount) {
      IERC20(token).approve(spender, type(uint).max);
    }
  }

  /// @dev Remove from array the item with given id and move the last item on it place
  ///      Use with mapping for keeping indexes in correct ordering
  function removeIndexed(
    uint256[] storage array,
    mapping(uint256 => uint256) storage indexes,
    uint256 id
  ) internal {
    uint256 lastId = array[array.length - 1];
    uint256 index = indexes[id];
    indexes[lastId] = index;
    indexes[id] = type(uint256).max;
    array[index] = lastId;
    array.pop();
  }

  /// @notice Return a-b OR zero if a < b
  function sub0(uint32 a, uint32 b) internal pure returns (uint32) {
    return a > b ? a - b : 0;
  }
}

File 9 of 11 : ERC721Holder.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../interfaces/IERC721Receiver.sol";

/**
 * @dev Implementation of the {IERC721Receiver} interface.
 *
 * Accepts all token transfers.
 * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
 */
contract ERC721Holder is IERC721Receiver {
  /**
   * @dev See {IERC721Receiver-onERC721Received}.
   *
   * Always returns `IERC721Receiver.onERC721Received.selector`.
   */
  function onERC721Received(
    address,
    address,
    uint256,
    bytes memory
  ) public virtual override returns (bytes4) {
    return this.onERC721Received.selector;
  }
}

File 10 of 11 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @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 EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * 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;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    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() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

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

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

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 11 of 11 : ERC2771Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)

pragma solidity ^0.8.1;

import "../interfaces/IAppErrors.sol";

/**
 * @dev Context variant with ERC2771 support.
 */
// based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/metatx/ERC2771Context.sol
abstract contract ERC2771Context {
  // for whitelist new relayers need to add new constants and update proxies
  address private constant GELATO_RELAY_1_BALANCE_ERC_2771 = 0xd8253782c45a12053594b9deB72d8e8aB2Fca54c;
  address private constant SACRA_RELAY = 0x52CEba41Da235Af367bFC0b0cCd3314cb901bB5F;

  function isTrustedForwarder(address forwarder) public view virtual returns (bool){
    return forwarder == GELATO_RELAY_1_BALANCE_ERC_2771 || forwarder == SACRA_RELAY;
  }

  function _msgSender() internal view virtual returns (address sender) {
    if (isTrustedForwarder(msg.sender)) {
      // The assembly code is more direct than the Solidity version using `abi.decode`.
      /// @solidity memory-safe-assembly
      assembly {
        sender := shr(96, calldataload(sub(calldatasize(), 20)))
      }
      return sender;
    } else {
      return msg.sender;
    }
  }

  function _msgData() internal view virtual returns (bytes calldata) {
    if (isTrustedForwarder(msg.sender)) {
      return msg.data[: msg.data.length - 20];
    } else {
      return msg.data;
    }
  }

  /// @notice Return true if given address is not a smart contract but a wallet address.
  /// @dev It is not 100% guarantee after EIP-3074 implementation, use it as an additional check.
  /// @return true if the address is a wallet.
  function _isNotSmartContract() internal view returns (bool) {
    return isTrustedForwarder(msg.sender) || msg.sender == tx.origin;
  }

  function onlyEOA() internal view {
    if (!_isNotSmartContract()) {
      revert IAppErrors.NotEOA(msg.sender);
    }
  }
}

Settings
{
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 50
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_depositToken","type":"address"},{"internalType":"uint256","name":"_positionDepositAmount","type":"uint256"},{"internalType":"address","name":"_feeRecipient","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"PawnShopAlreadyAnnounced","type":"error"},{"inputs":[],"name":"PawnShopAlreadyClaimed","type":"error"},{"inputs":[],"name":"PawnShopAuctionBidNotFound","type":"error"},{"inputs":[],"name":"PawnShopAuctionEnded","type":"error"},{"inputs":[],"name":"PawnShopAuctionNotEnded","type":"error"},{"inputs":[],"name":"PawnShopBidAlreadyExists","type":"error"},{"inputs":[],"name":"PawnShopBidClosed","type":"error"},{"inputs":[],"name":"PawnShopBidNotFound","type":"error"},{"inputs":[],"name":"PawnShopIncorrect","type":"error"},{"inputs":[],"name":"PawnShopNewBidTooLow","type":"error"},{"inputs":[],"name":"PawnShopNoBids","type":"error"},{"inputs":[],"name":"PawnShopNotBorrower","type":"error"},{"inputs":[],"name":"PawnShopNotLender","type":"error"},{"inputs":[],"name":"PawnShopNotOwner","type":"error"},{"inputs":[],"name":"PawnShopPosFeeAbsurdlyHigh","type":"error"},{"inputs":[],"name":"PawnShopPosFeeForInstantDealForbidden","type":"error"},{"inputs":[],"name":"PawnShopPositionClosed","type":"error"},{"inputs":[],"name":"PawnShopPositionExecuted","type":"error"},{"inputs":[],"name":"PawnShopPositionNotExecuted","type":"error"},{"inputs":[],"name":"PawnShopTimeLock","type":"error"},{"inputs":[],"name":"PawnShopTooEarlyToClaim","type":"error"},{"inputs":[],"name":"PawnShopTooHighValue","type":"error"},{"inputs":[],"name":"PawnShopTooLowBid","type":"error"},{"inputs":[],"name":"PawnShopWrongAddressValue","type":"error"},{"inputs":[],"name":"PawnShopWrongAmounts","type":"error"},{"inputs":[],"name":"PawnShopWrongBid","type":"error"},{"inputs":[],"name":"PawnShopWrongBidAmount","type":"error"},{"inputs":[],"name":"PawnShopWrongId","type":"error"},{"inputs":[],"name":"PawnShopWrongUintValue","type":"error"},{"inputs":[],"name":"PawnShopZeroAToken","type":"error"},{"inputs":[],"name":"PawnShopZeroAddress","type":"error"},{"inputs":[],"name":"PawnShopZeroCToken","type":"error"},{"inputs":[],"name":"PawnShopZeroFeeRecipient","type":"error"},{"inputs":[],"name":"PawnShopZeroOwner","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"posId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"}],"name":"AuctionBidAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"posId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"}],"name":"AuctionBidClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"posId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"lender","type":"address"}],"name":"AuctionBidOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"posId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"acquiredMoneyHolder","type":"address"},{"indexed":false,"internalType":"address","name":"lender","type":"address"}],"name":"BidExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"DepositAmountChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldToken","type":"address"},{"indexed":false,"internalType":"address","name":"newToken","type":"address"}],"name":"DepositTokenChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"newRecipient","type":"address"}],"name":"FeeRecipientChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"addressValue","type":"address"},{"indexed":false,"internalType":"uint256","name":"uintValue","type":"uint256"}],"name":"GovernanceActionAnnounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"PlatformFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"posId","type":"uint256"}],"name":"PositionClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"posId","type":"uint256"}],"name":"PositionClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"posId","type":"uint256"},{"indexed":false,"internalType":"address","name":"collateralToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"collateralTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"acquiredToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"acquiredAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"posDurationBlocks","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"posFee","type":"uint256"}],"name":"PositionOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"posId","type":"uint256"}],"name":"PositionRedeemed","type":"event"},{"inputs":[],"name":"AUCTION_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PLATFORM_FEE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIME_LOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"posId","type":"uint256"}],"name":"acceptAuctionBid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IPawnShop.GovernanceAction","name":"id","type":"uint8"},{"internalType":"address","name":"addressValue","type":"address"},{"internalType":"uint256","name":"uintValue","type":"uint256"}],"name":"announceGovernanceAction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"auctionBidCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"posId","type":"uint256"}],"name":"auctionBidSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"auctionBids","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"posId","type":"uint256"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"open","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"bid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"borrowerPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"}],"name":"borrowerPositionsSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegateContract","type":"address"},{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"clearDelegatedVotes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"bidId","type":"uint256"}],"name":"closeAuctionBid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createdBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"createdTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegateContract","type":"address"},{"internalType":"bytes32","name":"_id","type":"bytes32"},{"internalType":"address","name":"_delegate","type":"address"}],"name":"delegateVotes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getAssetType","outputs":[{"internalType":"enum IPawnShop.AssetType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"bidId","type":"uint256"}],"name":"getAuctionBid","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"posId","type":"uint256"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"open","type":"bool"}],"internalType":"struct IPawnShop.AuctionBid","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"posId","type":"uint256"}],"name":"getPosition","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"bool","name":"open","type":"bool"},{"internalType":"uint256","name":"minAuctionAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"posDurationBlocks","type":"uint256"},{"internalType":"uint256","name":"posFee","type":"uint256"},{"internalType":"uint256","name":"createdBlock","type":"uint256"},{"internalType":"uint256","name":"createdTs","type":"uint256"}],"internalType":"struct IPawnShop.PositionInfo","name":"info","type":"tuple"},{"components":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"enum IPawnShop.AssetType","name":"collateralType","type":"uint8"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"uint256","name":"collateralTokenId","type":"uint256"}],"internalType":"struct IPawnShop.PositionCollateral","name":"collateral","type":"tuple"},{"components":[{"internalType":"address","name":"acquiredToken","type":"address"},{"internalType":"uint256","name":"acquiredAmount","type":"uint256"}],"internalType":"struct IPawnShop.PositionAcquired","name":"acquired","type":"tuple"},{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"uint256","name":"posStartBlock","type":"uint256"},{"internalType":"uint256","name":"posStartTs","type":"uint256"},{"internalType":"uint256","name":"posEndTs","type":"uint256"}],"internalType":"struct IPawnShop.PositionExecution","name":"execution","type":"tuple"}],"internalType":"struct IPawnShop.Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isERC20","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isERC721","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lastAuctionBidTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"lenderOpenBids","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"lenderPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lender","type":"address"}],"name":"lenderPositionsSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"uint256","name":"_collateralTokenId","type":"uint256"},{"internalType":"address","name":"_acquiredToken","type":"address"},{"internalType":"uint256","name":"_acquiredAmount","type":"uint256"},{"internalType":"uint256","name":"_posDurationBlocks","type":"uint256"},{"internalType":"uint256","name":"_posFee","type":"uint256"},{"internalType":"uint256","name":"minAuctionAmount","type":"uint256"}],"name":"openPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"openPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openPositionsSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"platformFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum IPawnShop.IndexType","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"posIndexes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionDepositToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"positionToBidIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"positions","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"bool","name":"open","type":"bool"},{"internalType":"uint256","name":"minAuctionAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"posDurationBlocks","type":"uint256"},{"internalType":"uint256","name":"posFee","type":"uint256"},{"internalType":"uint256","name":"createdBlock","type":"uint256"},{"internalType":"uint256","name":"createdTs","type":"uint256"}],"internalType":"struct IPawnShop.PositionInfo","name":"info","type":"tuple"},{"components":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"enum IPawnShop.AssetType","name":"collateralType","type":"uint8"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"uint256","name":"collateralTokenId","type":"uint256"}],"internalType":"struct IPawnShop.PositionCollateral","name":"collateral","type":"tuple"},{"components":[{"internalType":"address","name":"acquiredToken","type":"address"},{"internalType":"uint256","name":"acquiredAmount","type":"uint256"}],"internalType":"struct IPawnShop.PositionAcquired","name":"acquired","type":"tuple"},{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"uint256","name":"posStartBlock","type":"uint256"},{"internalType":"uint256","name":"posStartTs","type":"uint256"},{"internalType":"uint256","name":"posEndTs","type":"uint256"}],"internalType":"struct IPawnShop.PositionExecution","name":"execution","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"positionsByAcquired","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"acquiredToken","type":"address"}],"name":"positionsByAcquiredSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"positionsByCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collateral","type":"address"}],"name":"positionsByCollateralSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newFeeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setPlatformFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setPositionDepositAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_value","type":"address"}],"name":"setPositionDepositToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IPawnShop.GovernanceAction","name":"","type":"uint8"}],"name":"timeLocks","outputs":[{"internalType":"uint256","name":"time","type":"uint256"},{"internalType":"address","name":"addressValue","type":"address"},{"internalType":"uint256","name":"uintValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"toRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60c06040526103e860035560016007556001600f553480156200002157600080fd5b50604051620046e2380380620046e2833981016040819052620000449162000108565b60016000556001600160a01b0384166200007157604051632de70ca360e11b815260040160405180910390fd5b6001600160a01b0381166200009957604051633cc5222160e11b815260040160405180910390fd5b600180546001600160a01b039586166001600160a01b03199182161790915560028054928616928216929092179091556005805493909416921691909117909155426080524360a0526004556200015c565b80516001600160a01b03811681146200010357600080fd5b919050565b600080600080608085870312156200011f57600080fd5b6200012a85620000eb565b93506200013a60208601620000eb565b9250604085015191506200015160608601620000eb565b905092959194509250565b60805160a0516145606200018260003960006104fa0152600061087201526145606000f3fe608060405234801561001057600080fd5b50600436106102ac5760003560e01c80638137884a11610173578063b8f1a962116100d4578063b8f1a962146106ce578063c50981a1146106e1578063c84d9665146106f4578063d2ec002514610776578063daa09e5414610789578063db006a751461079c578063db2dbb44146107af578063e0a09c68146107c2578063e5b595aa146107cc578063e74b981b146107df578063eb02c301146107f2578063eb07365f14610812578063f070ba031461086d578063ffa1ad741461089457600080fd5b80638137884a146105bc57806382bd0b8c146105c5578063884399be146105ce5780638da5cb5b146105d65780638e246762146105e9578063918f86741461061457806398584c0f1461061d57806399fbab88146106265780639c8ae0801461064f578063a126d60114610662578063a271e52514610675578063a27219e51461067f578063a93d789f146106a8578063b25a8ea3146106bb57600080fd5b806326232a2e1161021d57806326232a2e14610449578063263e0c1b14610452578063347d50c514610475578063379607f5146104bc5780633a5edc54146104cf5780633e87290b146104e25780634593144c146104f5578063469048401461051c57806352eb916f14610547578063572b6c051461055a578063598647f81461056d5780635a905e101461058057806363d5ab8d1461059357806381165ec61461059c57600080fd5b80624ce3d3146102b1578063032c49ed146102ed5780630580c0321461030d578063106f76351461032057806312e8e2c31461033557806313af40351461034857806314e5f4791461035b578063150b7a02146103845780631abda8e4146103af5780631c7c565a146103d85780631dcea853146103f85780632404e26d14610423578063248a19bb14610436575b600080fd5b6102da6102bf366004613e9d565b6001600160a01b03166000908152600c602052604090205490565b6040519081526020015b60405180910390f35b6103006102fb366004613e9d565b6108c6565b6040516102e49190613ef0565b6102da61031b366004613efe565b6108d7565b61033361032e366004613f28565b610908565b005b610333610343366004613f28565b610b9c565b610333610356366004613e9d565b610dc8565b6102da610369366004613e9d565b6001600160a01b03166000908152600a602052604090205490565b6103a2610392366004613f57565b630a85bd0160e11b949350505050565b6040516102e49190614033565b6102da6103bd366004613e9d565b6001600160a01b03166000908152600b602052604090205490565b6102da6103e6366004613f28565b60009081526012602052604090205490565b6102da610406366004614055565b600e60209081526000928352604080842090915290825290205481565b6102da610431366004613f28565b610fd7565b610333610444366004613f28565b610fe2565b6102da60035481565b610465610460366004613e9d565b6111aa565b60405190151581526020016102e4565b6104ad610483366004614073565b60066020526000908152604090208054600182015460029092015490916001600160a01b03169083565b6040516102e493929190614090565b6103336104ca366004613f28565b6111b5565b6102da6104dd3660046140af565b611363565b6103336104f0366004613efe565b611a37565b6102da7f000000000000000000000000000000000000000000000000000000000000000081565b60025461052f906001600160a01b031681565b6040516001600160a01b0390911681526020016102e4565b6102da610555366004613efe565b611ad0565b610465610568366004613e9d565b611aec565b61033361057b366004614119565b611b3a565b61033361058e36600461413b565b611c32565b6102da60075481565b6102da6105aa366004613f28565b60136020526000908152604090205481565b6102da6103e881565b6102da600f5481565b6009546102da565b60015461052f906001600160a01b031681565b6102da6105f7366004613efe565b601160209081526000928352604080842090915290825290205481565b6102da61271081565b6102da60045481565b610639610634366004613f28565b611db3565b6040516102e49a99989796959493929190614219565b61033361065d366004613f28565b611ee9565b610333610670366004613f28565b61213d565b6102da6201518081565b6102da61068d366004613e9d565b6001600160a01b03166000908152600d602052604090205490565b6102da6106b6366004613efe565b61249d565b6103336106c9366004613e9d565b6124b9565b6102da6106dc366004613efe565b6126a1565b6102da6106ef366004614119565b6126bd565b61073e610702366004613f28565b60106020526000908152604090208054600182015460028301546003840154600490940154929391926001600160a01b03909116919060ff1685565b6040805195865260208601949094526001600160a01b039092169284019290925260608301919091521515608082015260a0016102e4565b6102da610784366004613f28565b6126d9565b610465610797366004613e9d565b6126fa565b6103336107aa366004613f28565b612705565b60055461052f906001600160a01b031681565b6102da6202a30081565b6103336107da366004614294565b6128fa565b6103336107ed366004613e9d565b61299d565b610805610800366004613f28565b612bac565b6040516102e491906142d0565b610825610820366004613f28565b612d1e565b6040516102e4919081518152602080830151908201526040808301516001600160a01b0316908201526060808301519082015260809182015115159181019190915260a00190565b6102da7f000000000000000000000000000000000000000000000000000000000000000081565b6108b9604051806040016040528060068152602001650312e302e31360d41b81525081565b6040516102e4919061438f565b60006108d182612db8565b92915050565b600c60205281600052604060002081815481106108f357600080fd5b90600052602060002001600091509150505481565b610910612e2d565b60008181526010602052604081206002810154815491926001600160a01b039091169190036109525760405163c6b3721b60e01b815260040160405180910390fd5b600482015460ff1661097757604051634f98164160e11b815260040160405180910390fd5b61097f612e57565b6001600160a01b0316816001600160a01b0316146109b057604051631d70504f60e01b815260040160405180910390fd5b600182015460009081526008602090815260408083208054845260139092528220549091426109e262015180846143f4565b1090506000426109f562015180856143f4565b610a0290621275006143f4565b85546000908152601260205260408120549290911092509015610a5f57845460009081526012602052604081208054610a3d90600190614407565b81548110610a4d57610a4d61441a565b60009182526020909120015489149150505b808015610a695750825b80610a72575080155b80610a825750600485015460ff16155b80610a8a5750815b610aa75760405163459b792d60e11b815260040160405180910390fd5b6001600160a01b03808716600090815260116020908152604080832089548452909152808220919091556004808a01805460ff19169055600d88015460038b0154925163a9059cbb60e01b815293169263a9059cbb92610b09928b9201614430565b6020604051808303816000875af1158015610b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4c9190614449565b50845460408051918252602082018a90527f6a87dc49655b8e89257f75d88376c42ba5c050bf610a2c3f76148f127947f9c8910160405180910390a150505050505050610b996001600055565b50565b6001546001600160a01b0316610bb0612e57565b6001600160a01b031614610bd75760405163e0305dbd60e01b815260040160405180910390fd5b6002600081815260066020908152604080516060810182527f8819ef417987f8ae7a81f42cdfb18815282fe989326fbff903d13cf0e03ace29548082527f8819ef417987f8ae7a81f42cdfb18815282fe989326fbff903d13cf0e03ace2a546001600160a01b0316938201939093527f8819ef417987f8ae7a81f42cdfb18815282fe989326fbff903d13cf0e03ace2b549181019190915284911580610c7e575080514211155b15610c9c5760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b03831615610ce157826001600160a01b031681602001516001600160a01b031614610ce1576040516342b28e8560e01b815260040160405180910390fd5b8115610d0b5781816040015114610d0b57604051636c72ff3b60e11b815260040160405180910390fd5b6103e8851115610d2e57604051633724f56f60e21b815260040160405180910390fd5b60035460408051918252602082018790527fc98a8b10b63c929f7799380bb4a0c444c713ebf74d8732f944c915034121aad1910160405180910390a1600385905560066000856004811115610d8557610d85613eb8565b6004811115610d9657610d96613eb8565b8152602081019190915260400160009081208181556001810180546001600160a01b0319169055600201555050505050565b6001546001600160a01b0316610ddc612e57565b6001600160a01b031614610e035760405163e0305dbd60e01b815260040160405180910390fd5b600080805260066020908152604080516060810182527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8548082527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f9546001600160a01b0316938201939093527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4fa549181019190915283918391901580610eab575080514211155b15610ec95760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b03831615610f0e57826001600160a01b031681602001516001600160a01b031614610f0e576040516342b28e8560e01b815260040160405180910390fd5b8115610f385781816040015114610f3857604051636c72ff3b60e11b815260040160405180910390fd5b6001600160a01b038516610f5f57604051635e192a0160e11b815260040160405180910390fd5b6001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91610f9e916001600160a01b0390911690889061446b565b60405180910390a1600180546001600160a01b0319166001600160a01b03871617905560066000856004811115610d8557610d85613eb8565b60006108d182612e79565b6001546001600160a01b0316610ff6612e57565b6001600160a01b03161461101d5760405163e0305dbd60e01b815260040160405180910390fd5b6003600081815260066020908152604080516060810182527f75f96ab15d697e93042dc45b5c896c4b27e89bb6eaf39475c5c371cb2513f7d2548082527f75f96ab15d697e93042dc45b5c896c4b27e89bb6eaf39475c5c371cb2513f7d3546001600160a01b0316938201939093527f75f96ab15d697e93042dc45b5c896c4b27e89bb6eaf39475c5c371cb2513f7d45491810191909152849115806110c4575080514211155b156110e25760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b0383161561112757826001600160a01b031681602001516001600160a01b031614611127576040516342b28e8560e01b815260040160405180910390fd5b8115611151578181604001511461115157604051636c72ff3b60e11b815260040160405180910390fd5b60045460408051918252602082018790527fe8a90a4e7ae8a56c5c24412551b21d6b4557535da5309263e34d818103e15096910160405180910390a18460048190555060066000856004811115610d8557610d85613eb8565b60006108d18261302d565b6111bd612e2d565b6000818152600860205260409020805482146111ec5760405163385f723560e11b815260040160405180910390fd5b6111f4612e57565b600f8201546001600160a01b0390811691161461122457604051631d70504f60e01b815260040160405180910390fd5b6006810154601082015460009161123a916143f4565b905043811061125c576040516387b9d9ff60e01b815260040160405180910390fd5b600482015460ff16611281576040516331e52e2f60e11b815260040160405180910390fd5b61128a826130a2565b6040805160808101909152600a830180546001600160a01b03811683526113049291906020830190600160a01b900460ff1660018111156112cd576112cd613eb8565b60018111156112de576112de613eb8565b815260200160018201548152602001600282015481525050306112ff612e57565b61313e565b61130d836132b7565b611315612e57565b6001600160a01b03167ffa6e92366c16d5c789e26dd0b930fddd4e37c6115049c4d123cb73c529362fa98460405161134f91815260200190565b60405180910390a25050610b996001600055565b600061136d612e2d565b61137a612710600a614485565b83111561139a576040516392c9fd0160e01b815260040160405180910390fd5b831580156113a757508215155b156113c5576040516311c309ef60e21b815260040160405180910390fd5b871580156113d1575086155b156113ef5760405163c404a2e560e01b815260040160405180910390fd5b6001600160a01b0389166114165760405163b44bebfb60e01b815260040160405180910390fd5b6001600160a01b03861661143d57604051638573c7c160e01b815260040160405180910390fd5b60006114488a612db8565b9050600081600181111561145e5761145e613eb8565b14801561146a57508815155b8015611474575087155b1580156114a85750600181600181111561149057611490613eb8565b14801561149b575088155b80156114a657508715155b155b156114c657604051633d0b0d4360e21b815260040160405180910390fd5b6114ce613d95565b60006040518060800160405280888152602001878152602001438152602001428152509050600060405180608001604052808e6001600160a01b0316815260200185600181111561152157611521613eb8565b815260208082018f905260409182018e9052815180830183526001600160a01b038e1681528082018d90528251608081018452600080825281840181905281850181905260608201528351610140810190945260075484529394509291908101611589612e57565b6001600160a01b0390811682526005541660208201526004546040820152600160608201819052608082018b905260a082019690965260c081019490945260e084019290925261010090920191909152805160098054808501825560008290527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af01919091555490925061161d9190614407565b6000808052600e6020908152835182527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c81526040808320939093556001600160a01b038e16808352600a8252928220845181546001808201845583865293852001559290915290546116909190614407565b60016000818152600e6020908152845182527fa7c5ba7114a813b50159add3a36832908dc83db71d0b9a24c2ad0f83be95820781526040808320949094556001600160a01b038c16808352600b82529382208551815480860183558285529284209092019190915592905290546117079190614407565b60026000908152600e6020908152835182527f9adb202b1492743bc00c81d33cdc6423fa8c79109027eb6a845391e8fc1f048190526040812091909155600c9061174f612e57565b6001600160a01b031681526020808201929092526040016000908120835181546001818101845592845293832090930192909255600c9061178e612e57565b6001600160a01b031681526020810191909152604001600020546117b29190614407565b60036000818152600e6020908152845182527fe0283e559c29e31ee7f56467acc9dd307779c843a883aeeb3bf5c6128c9081448152604080832094909455845182526008808252918490208551815585820151600180830180546001600160a01b03199081166001600160a01b03948516179091558888015160028501805483169185169190911790556060808a015197850197909755608089015160048501805460ff191691151591909117905560a0890151600585015560c08901518051600686015580860151600786015597880151958401959095559590940151600982015560e08601518051600a83018054958616919096169081178655928101518796929591949193909284926001600160a81b03191690911790600160a01b9084908111156118e3576118e3613eb8565b021790555060408281015160018301556060928301516002909201919091556101008401518051600d850180546001600160a01b039283166001600160a01b031991821617909155602092830151600e870155610120909601518051600f870180549190931697169690961790558401516010840155830151601183015591909101516012909101556007805490600061197c8361449c565b9091555050805161198c90613358565b6119a28160e0015161199c612e57565b3061313e565b6119aa612e57565b8151604080519182526001600160a01b038e811660208401528282018e9052606083018d90528b8116608084015260a083018b905260c083018a905260e0830189905290519216917fb3a36ac05090f711e42b60c13a82d445eeea0e6aa81bb29143354d10f02de515918190036101000190a251915050611a2b6001600055565b98975050505050505050565b6001546001600160a01b0316611a4b612e57565b6001600160a01b031614611a725760405163e0305dbd60e01b815260040160405180910390fd5b60405163785f6df160e11b8152600481018290526001600160a01b0383169063f0bedbe290602401600060405180830381600087803b158015611ab457600080fd5b505af1158015611ac8573d6000803e3d6000fd5b505050505050565b600b60205281600052604060002081815481106108f357600080fd5b60006001600160a01b03821673d8253782c45a12053594b9deb72d8e8ab2fca54c14806108d157506001600160a01b0382167352ceba41da235af367bfc0b0ccd3314cb901bb5f1492915050565b611b42612e2d565b600082815260086020526040902080548314611b715760405163385f723560e11b815260040160405180910390fd5b600481015460ff16611b96576040516331e52e2f60e11b815260040160405180910390fd5b600f8101546001600160a01b031615611bc257604051634189c8eb60e01b815260040160405180910390fd5b600e81015415611c1157600e8101548214611bf057604051632b0706f360e11b815260040160405180910390fd5b611c0c81600084611bff612e57565b611c07612e57565b6133b9565b611c23565b611c238183611c1e612e57565b61387b565b50611c2e6001600055565b5050565b6001546001600160a01b0316611c46612e57565b6001600160a01b031614611c6d5760405163e0305dbd60e01b815260040160405180910390fd5b60066000846004811115611c8357611c83613eb8565b6004811115611c9457611c94613eb8565b815260208101919091526040016000205415611cc3576040516327b85cbd60e11b815260040160405180910390fd5b60405180606001604052806202a30042611cdd91906143f4565b81526001600160a01b038416602082015260400182905260066000856004811115611d0a57611d0a613eb8565b6004811115611d1b57611d1b613eb8565b8152602080820192909252604090810160002083518155918301516001830180546001600160a01b0319166001600160a01b0390921691909117905591909101516002909101557f86496aa80f046dc4404f94bce44e24d8e17dc1bb123e8c774ff23ce0e6f0aabe836004811115611d9557611d95613eb8565b8383604051611da693929190614090565b60405180910390a1505050565b600860208181526000928352604092839020805460018083015460028401546003850154600486015460058701548a5160808082018d5260068a0154825260078a0154828c01529a890154818d0152600989015460608201528b519a8b01909b52600a880180546001600160a01b038181168d52989c9689169b9590981699939860ff938416989297909594919391850192600160a01b900490911690811115611e5f57611e5f613eb8565b6001811115611e7057611e70613eb8565b8152600182015460208083019190915260029092015460409182015280518082018252600d8501546001600160a01b039081168252600e860154828501528251608081018452600f870154909116815260108601549381019390935260118501549183019190915260129093015460608201529091908a565b611ef1612e2d565b6000818152601360205260409020544290611f109062015180906143f4565b10611f2e5760405163459b792d60e11b815260040160405180910390fd5b6000818152601260205260408120549003611f5c57604051630ebe58ef60e11b815260040160405180910390fd5b60008181526012602052604081208054611f7890600190614407565b81548110611f8857611f8861441a565b600091825260208083209091015480835260109091526040822080549193509103611fc657604051630dcea1fb60e31b815260040160405180910390fd5b600481015460ff16611feb57604051634f98164160e11b815260040160405180910390fd5b8281600101541461200f57604051630c17e23d60e31b815260040160405180910390fd5b6000838152600860205260409020612025612e57565b60018201546001600160a01b039081169116146120555760405163632e534d60e01b815260040160405180910390fd5b600481015460ff1661207a576040516331e52e2f60e11b815260040160405180910390fd5b6003820154600e820181905560028301546120a491839186919030906001600160a01b03166133b9565b60028201546001600160a01b031660009081526011602090815260408083208454845290915281205560048201805460ff191690556120e1612e57565b6001600160a01b03167f493e1e7f0e9233f36d4697a11b43b59a1507e08e3c1f920549858785646ac179858460000154604051612128929190918252602082015260400190565b60405180910390a2505050610b996001600055565b612145612e2d565b6000818152600860205260409020805482146121745760405163385f723560e11b815260040160405180910390fd5b61217c612e57565b60018201546001600160a01b039081169116146121ac5760405163632e534d60e01b815260040160405180910390fd5b600f8101546001600160a01b0316156121d857604051634189c8eb60e01b815260040160405180910390fd5b600481015460ff166121fd576040516331e52e2f60e11b815260040160405180910390fd5b6040805161014081018252825481526001808401546001600160a01b0390811660208085019190915260028601548216848601526003860154606080860191909152600487015460ff9081161515608080880191909152600589015460a08801528751808201895260068a0154815260078a01548186015260088a0154818a015260098a01549381019390935260c08701929092528651918201909652600a87018054938416825261236496889560e08801959394929392850192600160a01b9004909116908111156122d2576122d2613eb8565b60018111156122e3576122e3613eb8565b8152600182015460208083019190915260029092015460409182015291835281518083018352600d8501546001600160a01b039081168252600e86015482840152848301919091528251608081018452600f860154909116815260108501549181019190915260118401548183015260129093015460608401520152613b9b565b60018101546001600160a01b03166000908152600c602052604081206123b391600e9060035b600481111561239b5761239b613eb8565b81526020019081526020016000208360000154613c26565b6040805160808101909152600a820180546001600160a01b03811683526124339291906020830190600160a01b900460ff1660018111156123f6576123f6613eb8565b600181111561240757612407613eb8565b8152600182810154602083015260029092015460409091015283015430906001600160a01b031661313e565b61243c826132b7565b60048101805460ff19169055612450612e57565b6001600160a01b03167fa9e0cdf27a7965d21573ebb808fbcb2c2a1cfd656e1ecf3f82549437b47406778360405161248a91815260200190565b60405180910390a250610b996001600055565b600d60205281600052604060002081815481106108f357600080fd5b6001546001600160a01b03166124cd612e57565b6001600160a01b0316146124f45760405163e0305dbd60e01b815260040160405180910390fd5b6004600081815260066020908152604080516060810182527fc5069e24aaadb2addc3e52e868fcf3f4f8acf5a87e24300992fd4540c2a87eed548082527fc5069e24aaadb2addc3e52e868fcf3f4f8acf5a87e24300992fd4540c2a87eee546001600160a01b0316938201939093527fc5069e24aaadb2addc3e52e868fcf3f4f8acf5a87e24300992fd4540c2a87eef5491810191909152849291158061259c575080514211155b156125ba5760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b038316156125ff57826001600160a01b031681602001516001600160a01b0316146125ff576040516342b28e8560e01b815260040160405180910390fd5b8115612629578181604001511461262957604051636c72ff3b60e11b815260040160405180910390fd5b6005546040517f709d4a2a735567787a6859678c4b234a262c4355d6d33796ddb4ef59f80c662191612668916001600160a01b0390911690889061446b565b60405180910390a1600580546001600160a01b0319166001600160a01b03871617905560066000856004811115610d8557610d85613eb8565b600a60205281600052604060002081815481106108f357600080fd5b601260205281600052604060002081815481106108f357600080fd5b600981815481106126e957600080fd5b600091825260209091200154905081565b60006108d182613c31565b61270d612e2d565b60008181526008602052604090208054821461273c5760405163385f723560e11b815260040160405180910390fd5b612744612e57565b60018201546001600160a01b039081169116146127745760405163632e534d60e01b815260040160405180910390fd5b600f8101546001600160a01b031661279f5760405163c4912b5360e01b815260040160405180910390fd5b600481015460ff166127c4576040516331e52e2f60e11b815260040160405180910390fd5b6127cd816130a2565b60006127d883612e79565b600d8301549091506001600160a01b03166323b872dd6127f6612e57565b600f8501546040516001600160e01b031960e085901b16815261282892916001600160a01b03169086906004016144b5565b6020604051808303816000875af1158015612847573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286b9190614449565b506040805160808101909152600a830180546001600160a01b03811683526128af9291906020830190600160a01b900460ff1660018111156112cd576112cd613eb8565b6128b8836132b7565b6128c0612e57565b6001600160a01b03167f573152bdc3a6b0ce7d310a9875f49776804dd1634202817985b567975731711f8460405161134f91815260200190565b6001546001600160a01b031661290e612e57565b6001600160a01b0316146129355760405163e0305dbd60e01b815260040160405180910390fd5b6040516317b0dca160e31b8152600481018390526001600160a01b03828116602483015284169063bd86e508906044015b600060405180830381600087803b15801561298057600080fd5b505af1158015612994573d6000803e3d6000fd5b50505050505050565b6001546001600160a01b03166129b1612e57565b6001600160a01b0316146129d85760405163e0305dbd60e01b815260040160405180910390fd5b6001600081815260066020908152604080516060810182527f3e5fec24aa4dc4e5aee2e025e51e1392c72a2500577559fae9665c6d52bd6a31548082527f3e5fec24aa4dc4e5aee2e025e51e1392c72a2500577559fae9665c6d52bd6a32546001600160a01b0316938201939093527f3e5fec24aa4dc4e5aee2e025e51e1392c72a2500577559fae9665c6d52bd6a3354918101919091528492911580612a80575080514211155b15612a9e5760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b03831615612ae357826001600160a01b031681602001516001600160a01b031614612ae3576040516342b28e8560e01b815260040160405180910390fd5b8115612b0d5781816040015114612b0d57604051636c72ff3b60e11b815260040160405180910390fd5b6001600160a01b038516612b3457604051635e192a0160e11b815260040160405180910390fd5b6002546040517f0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d91612b73916001600160a01b0390911690889061446b565b60405180910390a1600280546001600160a01b0319166001600160a01b03871617905560066000856004811115610d8557610d85613eb8565b612bb4613d95565b600082815260086020818152604092839020835161014081018552815481526001808301546001600160a01b039081168386015260028401548116838801526003840154606080850191909152600485015460ff9081161515608080870191909152600587015460a087015289518082018b52600688015481526007880154818a015298870154898b015260098701549289019290925260c08501979097528751908101909752600a8401805491821688529296939560e0880195850192600160a01b9092041690811115612c8b57612c8b613eb8565b6001811115612c9c57612c9c613eb8565b8152600182015460208083019190915260029092015460409182015291835281518083018352600d8501546001600160a01b039081168252600e86015482840152848301919091528251608081018452600f86015490911681526010850154918101919091526011840154818301526012909301546060840152015292915050565b612d5b6040518060a00160405280600081526020016000815260200160006001600160a01b03168152602001600081526020016000151581525090565b50600090815260106020908152604091829020825160a0810184528154815260018201549281019290925260028101546001600160a01b0316928201929092526003820154606082015260049091015460ff161515608082015290565b6000612dc382613c31565b15612dd057506001919050565b612dd98261302d565b15612de657506000919050565b60405162461bcd60e51b8152602060048201526012602482015271151414ce88155b9adb9bdddb88185cdcd95d60721b60448201526064015b60405180910390fd5b919050565b600260005403612e5057604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b6000612e6233611aec565b15612e74575060131936013560601c90565b503390565b6000818152600860208181526040808420815161014081018352815481526001808301546001600160a01b039081168387015260028401548116838601526003840154606080850191909152600485015460ff9081161515608080870191909152600587015460a087015287518082018952600688015481526007880154818b0152998701548a8901526009870154928a019290925260c08501989098528551908101909552600a84018054918216865288979396949560e08801959094919390850192600160a01b900490911690811115612f5757612f57613eb8565b6001811115612f6857612f68613eb8565b8152600182015460208083019190915260029092015460409182015291835281518083018352600d8501546001600160a01b039081168252600e86015482840152848301919091528251608081018452600f8601549091168152601085015481830152601185015481840152601290940154606085015291019190915260c082015181015161010083015190910151919250612710916130089190614485565b61301291906144d9565b8161010001516020015161302691906143f4565b9392505050565b6000816001600160a01b03166318160ddd6175306040518263ffffffff1660e01b81526004016020604051808303818786fa9350505050801561308d575060408051601f3d908101601f1916820190925261308a918101906144fb565b60015b61309957506000919050565b50600192915050565b6012810154156130c55760405163ea9883a360e01b815260040160405180910390fd5b60048101805460ff1916905542601282015560018101546001600160a01b03166000908152600c6020526040812061310191600e90600361238a565b600f8101546001600160a01b031615610b9957600f8101546001600160a01b03166000908152600d60205260408120610b9991600e90600461238a565b60008360200151600181111561315657613156613eb8565b0361321f57306001600160a01b038316036131e9578251604080850151905163a9059cbb60e01b81526001600160a01b039092169163a9059cbb916131a091859190600401614430565b6020604051808303816000875af11580156131bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e39190614449565b50505050565b825160408085015190516323b872dd60e01b81526001600160a01b03909216916323b872dd916131a091869186916004016144b5565b60018360200151600181111561323757613237613eb8565b0361327257825160608401516040516323b872dd60e01b81526001600160a01b03909216916323b872dd9161296691869186916004016144b5565b60405162461bcd60e51b81526020600482015260156024820152745450533a2057726f6e67206173736574207479706560581b6044820152606401612e1f565b505050565b600081815260086020526040902060028101546001600160a01b031615611c2e5760028101546001820154600383015460405163a9059cbb60e01b81526001600160a01b039384169363a9059cbb9361331593911691600401614430565b6020604051808303816000875af1158015613334573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b29190614449565b600081815260086020526040902060028101546001600160a01b031615611c2e576002810154600182015460038301546040516323b872dd60e01b81526001600160a01b03938416936323b872dd93613315939116913091906004016144b5565b6000612710600354856133cc9190614485565b6133d691906144d9565b905060006133e48286614407565b9050306001600160a01b0385160361347957600d870154600188015460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb92613430929116908590600401614430565b6020604051808303816000875af115801561344f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134739190614449565b50613575565b600d87015460018801546040516323b872dd60e01b81526001600160a01b03928316926323b872dd926134b69289929091169086906004016144b5565b6020604051808303816000875af11580156134d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134f99190614449565b50600d8701546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90613530908790309087906004016144b5565b6020604051808303816000875af115801561354f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135739190614449565b505b600d87015461358d906001600160a01b031683613caf565b8287600f0160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055504387600f01600101819055504287600f01600201819055506137178760405180610140016040529081600082015481526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600382015481526020016004820160009054906101000a900460ff1615151515815260200160058201548152602001600682016040518060800160405290816000820154815260200160018201548152602001600282015481526020016003820154815250508152602001600a82016040518060800160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016000820160149054906101000a900460ff1660018111156122d2576122d2613eb8565b6001600160a01b0383166000818152600d6020908152604082208a5481546001818101845583865293852001559290915290546137549190614407565b875460009081527fa1d6913cd9e08c872be3e7525cca82e4fc0fc298a783f19022be725b19be685a602052604081209190915560068801549003613819576040805160808101909152600a880180546001600160a01b03811683526138059291906020830190600160a01b900460ff1660018111156137d5576137d5613eb8565b60018111156137e6576137e6613eb8565b815260200160018201548152602001600282015481525050308561313e565b8654613810906132b7565b613819876130a2565b8654604080519182526020820188905281018690526001600160a01b038086166060830152841660808201527fb4a7227fb0dfeb98811f5d56165a8829f9656773c1b9dc94821d75c46f42f7639060a00160405180910390a150505050505050565b6001600160a01b038116600090815260116020908152604080832086548452909152902054156138be5760405163aca2258560e01b815260040160405180910390fd5b82600501548210156138e3576040516304f3be9f60e11b815260040160405180910390fd5b8254600090815260126020526040902054156139c9578254600090815260136020526040902054429061391a9062015180906143f4565b116139385760405163a508237960e01b815260040160405180910390fd5b82546000908152601260205260408120805461395690600190614407565b815481106139665761396661441a565b9060005260206000200154905060006010600083815260200190815260200160002090508360648260030154606e61399e9190614485565b6139a891906144d9565b106139c65760405163066881a960e51b815260040160405180910390fd5b50505b6040805160a081018252600f548152845460208083018290526001600160a01b038086168486018190526060850188905260016080860181905260009485526012845286852086518154928301825590865284862090910155885480855286852054918552601184528685209085529092529390912055600d8501549091166323b872dd613a55612e57565b30866040518463ffffffff1660e01b8152600401613a75939291906144b5565b6020604051808303816000875af1158015613a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab89190614449565b50835460009081526013602090815260408083204290558351835260108252808320845181559184015160018301558301516002820180546001600160a01b0319166001600160a01b039092169190911790556060830151600382015560808301516004909101805460ff1916911515919091179055600f805491613b3c8361449c565b90915550508354815160408051928352602083019190915281018490526001600160a01b03831660608201527f212de920a843943385be4d0be6f5375802a6c0eb13258959f94184f8599aa1f19060800160405180910390a150505050565b613bcf6009600e6000805b6004811115613bb757613bb7613eb8565b81526020019081526020016000208360000151613c26565b60e0810151516001600160a01b03166000908152600a60205260408120613bfa91600e906001613ba6565b610100810151516001600160a01b03166000908152600b60205260408120610b9991600e906002613ba6565b6132b2838383613cef565b6000816001600160a01b03166301ffc9a76175306380ac58cd60e01b6040518363ffffffff1660e01b8152600401613c699190614033565b6020604051808303818786fa93505050508015613ca3575060408051601f3d908101601f19168201909252613ca091810190614449565b60015b6108d157506000919050565b80600003613cbb575050565b60025460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb9261331592909116908590600401614430565b82546000908490613d0290600190614407565b81548110613d1257613d1261441a565b600091825260208083209091015484835290859052604080832080548385529184208290559285905260001990925585549092508290869083908110613d5a57613d5a61441a565b906000526020600020018190555084805480613d7857613d78614514565b600190038181906000526020600020016000905590555050505050565b6040518061014001604052806000815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160001515815260200160008152602001613e0a6040518060800160405280600081526020016000815260200160008152602001600081525090565b81526040805160808101825260008082526020808301829052828401829052606083018290528085019290925282518084018452818152918201529101908152602001613e81604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b905290565b80356001600160a01b0381168114612e2857600080fd5b600060208284031215613eaf57600080fd5b61302682613e86565b634e487b7160e01b600052602160045260246000fd5b60028110613eec57634e487b7160e01b600052602160045260246000fd5b9052565b602081016108d18284613ece565b60008060408385031215613f1157600080fd5b613f1a83613e86565b946020939093013593505050565b600060208284031215613f3a57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215613f6d57600080fd5b613f7685613e86565b9350613f8460208601613e86565b925060408501359150606085013567ffffffffffffffff80821115613fa857600080fd5b818701915087601f830112613fbc57600080fd5b813581811115613fce57613fce613f41565b604051601f8201601f19908116603f01168101908382118183101715613ff657613ff6613f41565b816040528281528a602084870101111561400f57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6001600160e01b031991909116815260200190565b60058110610b9957600080fd5b6000806040838503121561406857600080fd5b8235613f1a81614048565b60006020828403121561408557600080fd5b813561302681614048565b9283526001600160a01b03919091166020830152604082015260600190565b600080600080600080600080610100898b0312156140cc57600080fd5b6140d589613e86565b975060208901359650604089013595506140f160608a01613e86565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b6000806040838503121561412c57600080fd5b50508035926020909101359150565b60008060006060848603121561415057600080fd5b833561415b81614048565b925061416960208501613e86565b9150604084013590509250925092565b805182526020810151602083015260408101516040830152606081015160608301525050565b80516001600160a01b03168252602080820151906141bf90840182613ece565b5060408181015190830152606090810151910152565b80516001600160a01b03168252602090810151910152565b80516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b8a81526001600160a01b038a811660208301528916604082015260608101889052861515608082015260a08101869052610280810161425b60c0830187614179565b61426961014083018661419f565b6142776101c08301856141d5565b6142856102008301846141ed565b9b9a5050505050505050505050565b6000806000606084860312156142a957600080fd5b6142b284613e86565b9250602084013591506142c760408501613e86565b90509250925092565b815181526020808301516102808301916142f4908401826001600160a01b03169052565b50604083015161430f60408401826001600160a01b03169052565b5060608301516060830152608083015161432d608084018215159052565b5060a083015160a083015260c083015161434a60c0840182614179565b5060e083015161435e61014084018261419f565b506101008301516143736101c08401826141d5565b506101208301516143886102008401826141ed565b5092915050565b60006020808352835180602085015260005b818110156143bd578581018301518582016040015282016143a1565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052601160045260246000fd5b808201808211156108d1576108d16143de565b818103818111156108d1576108d16143de565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b03929092168252602082015260400190565b60006020828403121561445b57600080fd5b8151801515811461302657600080fd5b6001600160a01b0392831681529116602082015260400190565b80820281158282048414176108d1576108d16143de565b6000600182016144ae576144ae6143de565b5060010190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000826144f657634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561450d57600080fd5b5051919050565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220d25f358537997ae8171a8b21f2a548812a45b87cd8b9376ce9e8e3ed7c0f80ec64736f6c63430008170033000000000000000000000000bbbbb8c4364ec2ce52c59d2ed3e56f307e529a940000000000000000000000007ad5935ea295c4e743e4f2f5b4cda951f41223c20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000bbbbb8c4364ec2ce52c59d2ed3e56f307e529a94

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102ac5760003560e01c80638137884a11610173578063b8f1a962116100d4578063b8f1a962146106ce578063c50981a1146106e1578063c84d9665146106f4578063d2ec002514610776578063daa09e5414610789578063db006a751461079c578063db2dbb44146107af578063e0a09c68146107c2578063e5b595aa146107cc578063e74b981b146107df578063eb02c301146107f2578063eb07365f14610812578063f070ba031461086d578063ffa1ad741461089457600080fd5b80638137884a146105bc57806382bd0b8c146105c5578063884399be146105ce5780638da5cb5b146105d65780638e246762146105e9578063918f86741461061457806398584c0f1461061d57806399fbab88146106265780639c8ae0801461064f578063a126d60114610662578063a271e52514610675578063a27219e51461067f578063a93d789f146106a8578063b25a8ea3146106bb57600080fd5b806326232a2e1161021d57806326232a2e14610449578063263e0c1b14610452578063347d50c514610475578063379607f5146104bc5780633a5edc54146104cf5780633e87290b146104e25780634593144c146104f5578063469048401461051c57806352eb916f14610547578063572b6c051461055a578063598647f81461056d5780635a905e101461058057806363d5ab8d1461059357806381165ec61461059c57600080fd5b80624ce3d3146102b1578063032c49ed146102ed5780630580c0321461030d578063106f76351461032057806312e8e2c31461033557806313af40351461034857806314e5f4791461035b578063150b7a02146103845780631abda8e4146103af5780631c7c565a146103d85780631dcea853146103f85780632404e26d14610423578063248a19bb14610436575b600080fd5b6102da6102bf366004613e9d565b6001600160a01b03166000908152600c602052604090205490565b6040519081526020015b60405180910390f35b6103006102fb366004613e9d565b6108c6565b6040516102e49190613ef0565b6102da61031b366004613efe565b6108d7565b61033361032e366004613f28565b610908565b005b610333610343366004613f28565b610b9c565b610333610356366004613e9d565b610dc8565b6102da610369366004613e9d565b6001600160a01b03166000908152600a602052604090205490565b6103a2610392366004613f57565b630a85bd0160e11b949350505050565b6040516102e49190614033565b6102da6103bd366004613e9d565b6001600160a01b03166000908152600b602052604090205490565b6102da6103e6366004613f28565b60009081526012602052604090205490565b6102da610406366004614055565b600e60209081526000928352604080842090915290825290205481565b6102da610431366004613f28565b610fd7565b610333610444366004613f28565b610fe2565b6102da60035481565b610465610460366004613e9d565b6111aa565b60405190151581526020016102e4565b6104ad610483366004614073565b60066020526000908152604090208054600182015460029092015490916001600160a01b03169083565b6040516102e493929190614090565b6103336104ca366004613f28565b6111b5565b6102da6104dd3660046140af565b611363565b6103336104f0366004613efe565b611a37565b6102da7f000000000000000000000000000000000000000000000000000000000003887781565b60025461052f906001600160a01b031681565b6040516001600160a01b0390911681526020016102e4565b6102da610555366004613efe565b611ad0565b610465610568366004613e9d565b611aec565b61033361057b366004614119565b611b3a565b61033361058e36600461413b565b611c32565b6102da60075481565b6102da6105aa366004613f28565b60136020526000908152604090205481565b6102da6103e881565b6102da600f5481565b6009546102da565b60015461052f906001600160a01b031681565b6102da6105f7366004613efe565b601160209081526000928352604080842090915290825290205481565b6102da61271081565b6102da60045481565b610639610634366004613f28565b611db3565b6040516102e49a99989796959493929190614219565b61033361065d366004613f28565b611ee9565b610333610670366004613f28565b61213d565b6102da6201518081565b6102da61068d366004613e9d565b6001600160a01b03166000908152600d602052604090205490565b6102da6106b6366004613efe565b61249d565b6103336106c9366004613e9d565b6124b9565b6102da6106dc366004613efe565b6126a1565b6102da6106ef366004614119565b6126bd565b61073e610702366004613f28565b60106020526000908152604090208054600182015460028301546003840154600490940154929391926001600160a01b03909116919060ff1685565b6040805195865260208601949094526001600160a01b039092169284019290925260608301919091521515608082015260a0016102e4565b6102da610784366004613f28565b6126d9565b610465610797366004613e9d565b6126fa565b6103336107aa366004613f28565b612705565b60055461052f906001600160a01b031681565b6102da6202a30081565b6103336107da366004614294565b6128fa565b6103336107ed366004613e9d565b61299d565b610805610800366004613f28565b612bac565b6040516102e491906142d0565b610825610820366004613f28565b612d1e565b6040516102e4919081518152602080830151908201526040808301516001600160a01b0316908201526060808301519082015260809182015115159181019190915260a00190565b6102da7f000000000000000000000000000000000000000000000000000000006756ad2081565b6108b9604051806040016040528060068152602001650312e302e31360d41b81525081565b6040516102e4919061438f565b60006108d182612db8565b92915050565b600c60205281600052604060002081815481106108f357600080fd5b90600052602060002001600091509150505481565b610910612e2d565b60008181526010602052604081206002810154815491926001600160a01b039091169190036109525760405163c6b3721b60e01b815260040160405180910390fd5b600482015460ff1661097757604051634f98164160e11b815260040160405180910390fd5b61097f612e57565b6001600160a01b0316816001600160a01b0316146109b057604051631d70504f60e01b815260040160405180910390fd5b600182015460009081526008602090815260408083208054845260139092528220549091426109e262015180846143f4565b1090506000426109f562015180856143f4565b610a0290621275006143f4565b85546000908152601260205260408120549290911092509015610a5f57845460009081526012602052604081208054610a3d90600190614407565b81548110610a4d57610a4d61441a565b60009182526020909120015489149150505b808015610a695750825b80610a72575080155b80610a825750600485015460ff16155b80610a8a5750815b610aa75760405163459b792d60e11b815260040160405180910390fd5b6001600160a01b03808716600090815260116020908152604080832089548452909152808220919091556004808a01805460ff19169055600d88015460038b0154925163a9059cbb60e01b815293169263a9059cbb92610b09928b9201614430565b6020604051808303816000875af1158015610b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4c9190614449565b50845460408051918252602082018a90527f6a87dc49655b8e89257f75d88376c42ba5c050bf610a2c3f76148f127947f9c8910160405180910390a150505050505050610b996001600055565b50565b6001546001600160a01b0316610bb0612e57565b6001600160a01b031614610bd75760405163e0305dbd60e01b815260040160405180910390fd5b6002600081815260066020908152604080516060810182527f8819ef417987f8ae7a81f42cdfb18815282fe989326fbff903d13cf0e03ace29548082527f8819ef417987f8ae7a81f42cdfb18815282fe989326fbff903d13cf0e03ace2a546001600160a01b0316938201939093527f8819ef417987f8ae7a81f42cdfb18815282fe989326fbff903d13cf0e03ace2b549181019190915284911580610c7e575080514211155b15610c9c5760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b03831615610ce157826001600160a01b031681602001516001600160a01b031614610ce1576040516342b28e8560e01b815260040160405180910390fd5b8115610d0b5781816040015114610d0b57604051636c72ff3b60e11b815260040160405180910390fd5b6103e8851115610d2e57604051633724f56f60e21b815260040160405180910390fd5b60035460408051918252602082018790527fc98a8b10b63c929f7799380bb4a0c444c713ebf74d8732f944c915034121aad1910160405180910390a1600385905560066000856004811115610d8557610d85613eb8565b6004811115610d9657610d96613eb8565b8152602081019190915260400160009081208181556001810180546001600160a01b0319169055600201555050505050565b6001546001600160a01b0316610ddc612e57565b6001600160a01b031614610e035760405163e0305dbd60e01b815260040160405180910390fd5b600080805260066020908152604080516060810182527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f8548082527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f9546001600160a01b0316938201939093527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4fa549181019190915283918391901580610eab575080514211155b15610ec95760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b03831615610f0e57826001600160a01b031681602001516001600160a01b031614610f0e576040516342b28e8560e01b815260040160405180910390fd5b8115610f385781816040015114610f3857604051636c72ff3b60e11b815260040160405180910390fd5b6001600160a01b038516610f5f57604051635e192a0160e11b815260040160405180910390fd5b6001546040517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91610f9e916001600160a01b0390911690889061446b565b60405180910390a1600180546001600160a01b0319166001600160a01b03871617905560066000856004811115610d8557610d85613eb8565b60006108d182612e79565b6001546001600160a01b0316610ff6612e57565b6001600160a01b03161461101d5760405163e0305dbd60e01b815260040160405180910390fd5b6003600081815260066020908152604080516060810182527f75f96ab15d697e93042dc45b5c896c4b27e89bb6eaf39475c5c371cb2513f7d2548082527f75f96ab15d697e93042dc45b5c896c4b27e89bb6eaf39475c5c371cb2513f7d3546001600160a01b0316938201939093527f75f96ab15d697e93042dc45b5c896c4b27e89bb6eaf39475c5c371cb2513f7d45491810191909152849115806110c4575080514211155b156110e25760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b0383161561112757826001600160a01b031681602001516001600160a01b031614611127576040516342b28e8560e01b815260040160405180910390fd5b8115611151578181604001511461115157604051636c72ff3b60e11b815260040160405180910390fd5b60045460408051918252602082018790527fe8a90a4e7ae8a56c5c24412551b21d6b4557535da5309263e34d818103e15096910160405180910390a18460048190555060066000856004811115610d8557610d85613eb8565b60006108d18261302d565b6111bd612e2d565b6000818152600860205260409020805482146111ec5760405163385f723560e11b815260040160405180910390fd5b6111f4612e57565b600f8201546001600160a01b0390811691161461122457604051631d70504f60e01b815260040160405180910390fd5b6006810154601082015460009161123a916143f4565b905043811061125c576040516387b9d9ff60e01b815260040160405180910390fd5b600482015460ff16611281576040516331e52e2f60e11b815260040160405180910390fd5b61128a826130a2565b6040805160808101909152600a830180546001600160a01b03811683526113049291906020830190600160a01b900460ff1660018111156112cd576112cd613eb8565b60018111156112de576112de613eb8565b815260200160018201548152602001600282015481525050306112ff612e57565b61313e565b61130d836132b7565b611315612e57565b6001600160a01b03167ffa6e92366c16d5c789e26dd0b930fddd4e37c6115049c4d123cb73c529362fa98460405161134f91815260200190565b60405180910390a25050610b996001600055565b600061136d612e2d565b61137a612710600a614485565b83111561139a576040516392c9fd0160e01b815260040160405180910390fd5b831580156113a757508215155b156113c5576040516311c309ef60e21b815260040160405180910390fd5b871580156113d1575086155b156113ef5760405163c404a2e560e01b815260040160405180910390fd5b6001600160a01b0389166114165760405163b44bebfb60e01b815260040160405180910390fd5b6001600160a01b03861661143d57604051638573c7c160e01b815260040160405180910390fd5b60006114488a612db8565b9050600081600181111561145e5761145e613eb8565b14801561146a57508815155b8015611474575087155b1580156114a85750600181600181111561149057611490613eb8565b14801561149b575088155b80156114a657508715155b155b156114c657604051633d0b0d4360e21b815260040160405180910390fd5b6114ce613d95565b60006040518060800160405280888152602001878152602001438152602001428152509050600060405180608001604052808e6001600160a01b0316815260200185600181111561152157611521613eb8565b815260208082018f905260409182018e9052815180830183526001600160a01b038e1681528082018d90528251608081018452600080825281840181905281850181905260608201528351610140810190945260075484529394509291908101611589612e57565b6001600160a01b0390811682526005541660208201526004546040820152600160608201819052608082018b905260a082019690965260c081019490945260e084019290925261010090920191909152805160098054808501825560008290527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af01919091555490925061161d9190614407565b6000808052600e6020908152835182527fe710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881c81526040808320939093556001600160a01b038e16808352600a8252928220845181546001808201845583865293852001559290915290546116909190614407565b60016000818152600e6020908152845182527fa7c5ba7114a813b50159add3a36832908dc83db71d0b9a24c2ad0f83be95820781526040808320949094556001600160a01b038c16808352600b82529382208551815480860183558285529284209092019190915592905290546117079190614407565b60026000908152600e6020908152835182527f9adb202b1492743bc00c81d33cdc6423fa8c79109027eb6a845391e8fc1f048190526040812091909155600c9061174f612e57565b6001600160a01b031681526020808201929092526040016000908120835181546001818101845592845293832090930192909255600c9061178e612e57565b6001600160a01b031681526020810191909152604001600020546117b29190614407565b60036000818152600e6020908152845182527fe0283e559c29e31ee7f56467acc9dd307779c843a883aeeb3bf5c6128c9081448152604080832094909455845182526008808252918490208551815585820151600180830180546001600160a01b03199081166001600160a01b03948516179091558888015160028501805483169185169190911790556060808a015197850197909755608089015160048501805460ff191691151591909117905560a0890151600585015560c08901518051600686015580860151600786015597880151958401959095559590940151600982015560e08601518051600a83018054958616919096169081178655928101518796929591949193909284926001600160a81b03191690911790600160a01b9084908111156118e3576118e3613eb8565b021790555060408281015160018301556060928301516002909201919091556101008401518051600d850180546001600160a01b039283166001600160a01b031991821617909155602092830151600e870155610120909601518051600f870180549190931697169690961790558401516010840155830151601183015591909101516012909101556007805490600061197c8361449c565b9091555050805161198c90613358565b6119a28160e0015161199c612e57565b3061313e565b6119aa612e57565b8151604080519182526001600160a01b038e811660208401528282018e9052606083018d90528b8116608084015260a083018b905260c083018a905260e0830189905290519216917fb3a36ac05090f711e42b60c13a82d445eeea0e6aa81bb29143354d10f02de515918190036101000190a251915050611a2b6001600055565b98975050505050505050565b6001546001600160a01b0316611a4b612e57565b6001600160a01b031614611a725760405163e0305dbd60e01b815260040160405180910390fd5b60405163785f6df160e11b8152600481018290526001600160a01b0383169063f0bedbe290602401600060405180830381600087803b158015611ab457600080fd5b505af1158015611ac8573d6000803e3d6000fd5b505050505050565b600b60205281600052604060002081815481106108f357600080fd5b60006001600160a01b03821673d8253782c45a12053594b9deb72d8e8ab2fca54c14806108d157506001600160a01b0382167352ceba41da235af367bfc0b0ccd3314cb901bb5f1492915050565b611b42612e2d565b600082815260086020526040902080548314611b715760405163385f723560e11b815260040160405180910390fd5b600481015460ff16611b96576040516331e52e2f60e11b815260040160405180910390fd5b600f8101546001600160a01b031615611bc257604051634189c8eb60e01b815260040160405180910390fd5b600e81015415611c1157600e8101548214611bf057604051632b0706f360e11b815260040160405180910390fd5b611c0c81600084611bff612e57565b611c07612e57565b6133b9565b611c23565b611c238183611c1e612e57565b61387b565b50611c2e6001600055565b5050565b6001546001600160a01b0316611c46612e57565b6001600160a01b031614611c6d5760405163e0305dbd60e01b815260040160405180910390fd5b60066000846004811115611c8357611c83613eb8565b6004811115611c9457611c94613eb8565b815260208101919091526040016000205415611cc3576040516327b85cbd60e11b815260040160405180910390fd5b60405180606001604052806202a30042611cdd91906143f4565b81526001600160a01b038416602082015260400182905260066000856004811115611d0a57611d0a613eb8565b6004811115611d1b57611d1b613eb8565b8152602080820192909252604090810160002083518155918301516001830180546001600160a01b0319166001600160a01b0390921691909117905591909101516002909101557f86496aa80f046dc4404f94bce44e24d8e17dc1bb123e8c774ff23ce0e6f0aabe836004811115611d9557611d95613eb8565b8383604051611da693929190614090565b60405180910390a1505050565b600860208181526000928352604092839020805460018083015460028401546003850154600486015460058701548a5160808082018d5260068a0154825260078a0154828c01529a890154818d0152600989015460608201528b519a8b01909b52600a880180546001600160a01b038181168d52989c9689169b9590981699939860ff938416989297909594919391850192600160a01b900490911690811115611e5f57611e5f613eb8565b6001811115611e7057611e70613eb8565b8152600182015460208083019190915260029092015460409182015280518082018252600d8501546001600160a01b039081168252600e860154828501528251608081018452600f870154909116815260108601549381019390935260118501549183019190915260129093015460608201529091908a565b611ef1612e2d565b6000818152601360205260409020544290611f109062015180906143f4565b10611f2e5760405163459b792d60e11b815260040160405180910390fd5b6000818152601260205260408120549003611f5c57604051630ebe58ef60e11b815260040160405180910390fd5b60008181526012602052604081208054611f7890600190614407565b81548110611f8857611f8861441a565b600091825260208083209091015480835260109091526040822080549193509103611fc657604051630dcea1fb60e31b815260040160405180910390fd5b600481015460ff16611feb57604051634f98164160e11b815260040160405180910390fd5b8281600101541461200f57604051630c17e23d60e31b815260040160405180910390fd5b6000838152600860205260409020612025612e57565b60018201546001600160a01b039081169116146120555760405163632e534d60e01b815260040160405180910390fd5b600481015460ff1661207a576040516331e52e2f60e11b815260040160405180910390fd5b6003820154600e820181905560028301546120a491839186919030906001600160a01b03166133b9565b60028201546001600160a01b031660009081526011602090815260408083208454845290915281205560048201805460ff191690556120e1612e57565b6001600160a01b03167f493e1e7f0e9233f36d4697a11b43b59a1507e08e3c1f920549858785646ac179858460000154604051612128929190918252602082015260400190565b60405180910390a2505050610b996001600055565b612145612e2d565b6000818152600860205260409020805482146121745760405163385f723560e11b815260040160405180910390fd5b61217c612e57565b60018201546001600160a01b039081169116146121ac5760405163632e534d60e01b815260040160405180910390fd5b600f8101546001600160a01b0316156121d857604051634189c8eb60e01b815260040160405180910390fd5b600481015460ff166121fd576040516331e52e2f60e11b815260040160405180910390fd5b6040805161014081018252825481526001808401546001600160a01b0390811660208085019190915260028601548216848601526003860154606080860191909152600487015460ff9081161515608080880191909152600589015460a08801528751808201895260068a0154815260078a01548186015260088a0154818a015260098a01549381019390935260c08701929092528651918201909652600a87018054938416825261236496889560e08801959394929392850192600160a01b9004909116908111156122d2576122d2613eb8565b60018111156122e3576122e3613eb8565b8152600182015460208083019190915260029092015460409182015291835281518083018352600d8501546001600160a01b039081168252600e86015482840152848301919091528251608081018452600f860154909116815260108501549181019190915260118401548183015260129093015460608401520152613b9b565b60018101546001600160a01b03166000908152600c602052604081206123b391600e9060035b600481111561239b5761239b613eb8565b81526020019081526020016000208360000154613c26565b6040805160808101909152600a820180546001600160a01b03811683526124339291906020830190600160a01b900460ff1660018111156123f6576123f6613eb8565b600181111561240757612407613eb8565b8152600182810154602083015260029092015460409091015283015430906001600160a01b031661313e565b61243c826132b7565b60048101805460ff19169055612450612e57565b6001600160a01b03167fa9e0cdf27a7965d21573ebb808fbcb2c2a1cfd656e1ecf3f82549437b47406778360405161248a91815260200190565b60405180910390a250610b996001600055565b600d60205281600052604060002081815481106108f357600080fd5b6001546001600160a01b03166124cd612e57565b6001600160a01b0316146124f45760405163e0305dbd60e01b815260040160405180910390fd5b6004600081815260066020908152604080516060810182527fc5069e24aaadb2addc3e52e868fcf3f4f8acf5a87e24300992fd4540c2a87eed548082527fc5069e24aaadb2addc3e52e868fcf3f4f8acf5a87e24300992fd4540c2a87eee546001600160a01b0316938201939093527fc5069e24aaadb2addc3e52e868fcf3f4f8acf5a87e24300992fd4540c2a87eef5491810191909152849291158061259c575080514211155b156125ba5760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b038316156125ff57826001600160a01b031681602001516001600160a01b0316146125ff576040516342b28e8560e01b815260040160405180910390fd5b8115612629578181604001511461262957604051636c72ff3b60e11b815260040160405180910390fd5b6005546040517f709d4a2a735567787a6859678c4b234a262c4355d6d33796ddb4ef59f80c662191612668916001600160a01b0390911690889061446b565b60405180910390a1600580546001600160a01b0319166001600160a01b03871617905560066000856004811115610d8557610d85613eb8565b600a60205281600052604060002081815481106108f357600080fd5b601260205281600052604060002081815481106108f357600080fd5b600981815481106126e957600080fd5b600091825260209091200154905081565b60006108d182613c31565b61270d612e2d565b60008181526008602052604090208054821461273c5760405163385f723560e11b815260040160405180910390fd5b612744612e57565b60018201546001600160a01b039081169116146127745760405163632e534d60e01b815260040160405180910390fd5b600f8101546001600160a01b031661279f5760405163c4912b5360e01b815260040160405180910390fd5b600481015460ff166127c4576040516331e52e2f60e11b815260040160405180910390fd5b6127cd816130a2565b60006127d883612e79565b600d8301549091506001600160a01b03166323b872dd6127f6612e57565b600f8501546040516001600160e01b031960e085901b16815261282892916001600160a01b03169086906004016144b5565b6020604051808303816000875af1158015612847573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286b9190614449565b506040805160808101909152600a830180546001600160a01b03811683526128af9291906020830190600160a01b900460ff1660018111156112cd576112cd613eb8565b6128b8836132b7565b6128c0612e57565b6001600160a01b03167f573152bdc3a6b0ce7d310a9875f49776804dd1634202817985b567975731711f8460405161134f91815260200190565b6001546001600160a01b031661290e612e57565b6001600160a01b0316146129355760405163e0305dbd60e01b815260040160405180910390fd5b6040516317b0dca160e31b8152600481018390526001600160a01b03828116602483015284169063bd86e508906044015b600060405180830381600087803b15801561298057600080fd5b505af1158015612994573d6000803e3d6000fd5b50505050505050565b6001546001600160a01b03166129b1612e57565b6001600160a01b0316146129d85760405163e0305dbd60e01b815260040160405180910390fd5b6001600081815260066020908152604080516060810182527f3e5fec24aa4dc4e5aee2e025e51e1392c72a2500577559fae9665c6d52bd6a31548082527f3e5fec24aa4dc4e5aee2e025e51e1392c72a2500577559fae9665c6d52bd6a32546001600160a01b0316938201939093527f3e5fec24aa4dc4e5aee2e025e51e1392c72a2500577559fae9665c6d52bd6a3354918101919091528492911580612a80575080514211155b15612a9e5760405163cfb1217b60e01b815260040160405180910390fd5b6001600160a01b03831615612ae357826001600160a01b031681602001516001600160a01b031614612ae3576040516342b28e8560e01b815260040160405180910390fd5b8115612b0d5781816040015114612b0d57604051636c72ff3b60e11b815260040160405180910390fd5b6001600160a01b038516612b3457604051635e192a0160e11b815260040160405180910390fd5b6002546040517f0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d91612b73916001600160a01b0390911690889061446b565b60405180910390a1600280546001600160a01b0319166001600160a01b03871617905560066000856004811115610d8557610d85613eb8565b612bb4613d95565b600082815260086020818152604092839020835161014081018552815481526001808301546001600160a01b039081168386015260028401548116838801526003840154606080850191909152600485015460ff9081161515608080870191909152600587015460a087015289518082018b52600688015481526007880154818a015298870154898b015260098701549289019290925260c08501979097528751908101909752600a8401805491821688529296939560e0880195850192600160a01b9092041690811115612c8b57612c8b613eb8565b6001811115612c9c57612c9c613eb8565b8152600182015460208083019190915260029092015460409182015291835281518083018352600d8501546001600160a01b039081168252600e86015482840152848301919091528251608081018452600f86015490911681526010850154918101919091526011840154818301526012909301546060840152015292915050565b612d5b6040518060a00160405280600081526020016000815260200160006001600160a01b03168152602001600081526020016000151581525090565b50600090815260106020908152604091829020825160a0810184528154815260018201549281019290925260028101546001600160a01b0316928201929092526003820154606082015260049091015460ff161515608082015290565b6000612dc382613c31565b15612dd057506001919050565b612dd98261302d565b15612de657506000919050565b60405162461bcd60e51b8152602060048201526012602482015271151414ce88155b9adb9bdddb88185cdcd95d60721b60448201526064015b60405180910390fd5b919050565b600260005403612e5057604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b6000612e6233611aec565b15612e74575060131936013560601c90565b503390565b6000818152600860208181526040808420815161014081018352815481526001808301546001600160a01b039081168387015260028401548116838601526003840154606080850191909152600485015460ff9081161515608080870191909152600587015460a087015287518082018952600688015481526007880154818b0152998701548a8901526009870154928a019290925260c08501989098528551908101909552600a84018054918216865288979396949560e08801959094919390850192600160a01b900490911690811115612f5757612f57613eb8565b6001811115612f6857612f68613eb8565b8152600182015460208083019190915260029092015460409182015291835281518083018352600d8501546001600160a01b039081168252600e86015482840152848301919091528251608081018452600f8601549091168152601085015481830152601185015481840152601290940154606085015291019190915260c082015181015161010083015190910151919250612710916130089190614485565b61301291906144d9565b8161010001516020015161302691906143f4565b9392505050565b6000816001600160a01b03166318160ddd6175306040518263ffffffff1660e01b81526004016020604051808303818786fa9350505050801561308d575060408051601f3d908101601f1916820190925261308a918101906144fb565b60015b61309957506000919050565b50600192915050565b6012810154156130c55760405163ea9883a360e01b815260040160405180910390fd5b60048101805460ff1916905542601282015560018101546001600160a01b03166000908152600c6020526040812061310191600e90600361238a565b600f8101546001600160a01b031615610b9957600f8101546001600160a01b03166000908152600d60205260408120610b9991600e90600461238a565b60008360200151600181111561315657613156613eb8565b0361321f57306001600160a01b038316036131e9578251604080850151905163a9059cbb60e01b81526001600160a01b039092169163a9059cbb916131a091859190600401614430565b6020604051808303816000875af11580156131bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e39190614449565b50505050565b825160408085015190516323b872dd60e01b81526001600160a01b03909216916323b872dd916131a091869186916004016144b5565b60018360200151600181111561323757613237613eb8565b0361327257825160608401516040516323b872dd60e01b81526001600160a01b03909216916323b872dd9161296691869186916004016144b5565b60405162461bcd60e51b81526020600482015260156024820152745450533a2057726f6e67206173736574207479706560581b6044820152606401612e1f565b505050565b600081815260086020526040902060028101546001600160a01b031615611c2e5760028101546001820154600383015460405163a9059cbb60e01b81526001600160a01b039384169363a9059cbb9361331593911691600401614430565b6020604051808303816000875af1158015613334573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b29190614449565b600081815260086020526040902060028101546001600160a01b031615611c2e576002810154600182015460038301546040516323b872dd60e01b81526001600160a01b03938416936323b872dd93613315939116913091906004016144b5565b6000612710600354856133cc9190614485565b6133d691906144d9565b905060006133e48286614407565b9050306001600160a01b0385160361347957600d870154600188015460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb92613430929116908590600401614430565b6020604051808303816000875af115801561344f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134739190614449565b50613575565b600d87015460018801546040516323b872dd60e01b81526001600160a01b03928316926323b872dd926134b69289929091169086906004016144b5565b6020604051808303816000875af11580156134d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134f99190614449565b50600d8701546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90613530908790309087906004016144b5565b6020604051808303816000875af115801561354f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135739190614449565b505b600d87015461358d906001600160a01b031683613caf565b8287600f0160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055504387600f01600101819055504287600f01600201819055506137178760405180610140016040529081600082015481526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600382015481526020016004820160009054906101000a900460ff1615151515815260200160058201548152602001600682016040518060800160405290816000820154815260200160018201548152602001600282015481526020016003820154815250508152602001600a82016040518060800160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016000820160149054906101000a900460ff1660018111156122d2576122d2613eb8565b6001600160a01b0383166000818152600d6020908152604082208a5481546001818101845583865293852001559290915290546137549190614407565b875460009081527fa1d6913cd9e08c872be3e7525cca82e4fc0fc298a783f19022be725b19be685a602052604081209190915560068801549003613819576040805160808101909152600a880180546001600160a01b03811683526138059291906020830190600160a01b900460ff1660018111156137d5576137d5613eb8565b60018111156137e6576137e6613eb8565b815260200160018201548152602001600282015481525050308561313e565b8654613810906132b7565b613819876130a2565b8654604080519182526020820188905281018690526001600160a01b038086166060830152841660808201527fb4a7227fb0dfeb98811f5d56165a8829f9656773c1b9dc94821d75c46f42f7639060a00160405180910390a150505050505050565b6001600160a01b038116600090815260116020908152604080832086548452909152902054156138be5760405163aca2258560e01b815260040160405180910390fd5b82600501548210156138e3576040516304f3be9f60e11b815260040160405180910390fd5b8254600090815260126020526040902054156139c9578254600090815260136020526040902054429061391a9062015180906143f4565b116139385760405163a508237960e01b815260040160405180910390fd5b82546000908152601260205260408120805461395690600190614407565b815481106139665761396661441a565b9060005260206000200154905060006010600083815260200190815260200160002090508360648260030154606e61399e9190614485565b6139a891906144d9565b106139c65760405163066881a960e51b815260040160405180910390fd5b50505b6040805160a081018252600f548152845460208083018290526001600160a01b038086168486018190526060850188905260016080860181905260009485526012845286852086518154928301825590865284862090910155885480855286852054918552601184528685209085529092529390912055600d8501549091166323b872dd613a55612e57565b30866040518463ffffffff1660e01b8152600401613a75939291906144b5565b6020604051808303816000875af1158015613a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab89190614449565b50835460009081526013602090815260408083204290558351835260108252808320845181559184015160018301558301516002820180546001600160a01b0319166001600160a01b039092169190911790556060830151600382015560808301516004909101805460ff1916911515919091179055600f805491613b3c8361449c565b90915550508354815160408051928352602083019190915281018490526001600160a01b03831660608201527f212de920a843943385be4d0be6f5375802a6c0eb13258959f94184f8599aa1f19060800160405180910390a150505050565b613bcf6009600e6000805b6004811115613bb757613bb7613eb8565b81526020019081526020016000208360000151613c26565b60e0810151516001600160a01b03166000908152600a60205260408120613bfa91600e906001613ba6565b610100810151516001600160a01b03166000908152600b60205260408120610b9991600e906002613ba6565b6132b2838383613cef565b6000816001600160a01b03166301ffc9a76175306380ac58cd60e01b6040518363ffffffff1660e01b8152600401613c699190614033565b6020604051808303818786fa93505050508015613ca3575060408051601f3d908101601f19168201909252613ca091810190614449565b60015b6108d157506000919050565b80600003613cbb575050565b60025460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb9261331592909116908590600401614430565b82546000908490613d0290600190614407565b81548110613d1257613d1261441a565b600091825260208083209091015484835290859052604080832080548385529184208290559285905260001990925585549092508290869083908110613d5a57613d5a61441a565b906000526020600020018190555084805480613d7857613d78614514565b600190038181906000526020600020016000905590555050505050565b6040518061014001604052806000815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160001515815260200160008152602001613e0a6040518060800160405280600081526020016000815260200160008152602001600081525090565b81526040805160808101825260008082526020808301829052828401829052606083018290528085019290925282518084018452818152918201529101908152602001613e81604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b905290565b80356001600160a01b0381168114612e2857600080fd5b600060208284031215613eaf57600080fd5b61302682613e86565b634e487b7160e01b600052602160045260246000fd5b60028110613eec57634e487b7160e01b600052602160045260246000fd5b9052565b602081016108d18284613ece565b60008060408385031215613f1157600080fd5b613f1a83613e86565b946020939093013593505050565b600060208284031215613f3a57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215613f6d57600080fd5b613f7685613e86565b9350613f8460208601613e86565b925060408501359150606085013567ffffffffffffffff80821115613fa857600080fd5b818701915087601f830112613fbc57600080fd5b813581811115613fce57613fce613f41565b604051601f8201601f19908116603f01168101908382118183101715613ff657613ff6613f41565b816040528281528a602084870101111561400f57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6001600160e01b031991909116815260200190565b60058110610b9957600080fd5b6000806040838503121561406857600080fd5b8235613f1a81614048565b60006020828403121561408557600080fd5b813561302681614048565b9283526001600160a01b03919091166020830152604082015260600190565b600080600080600080600080610100898b0312156140cc57600080fd5b6140d589613e86565b975060208901359650604089013595506140f160608a01613e86565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b6000806040838503121561412c57600080fd5b50508035926020909101359150565b60008060006060848603121561415057600080fd5b833561415b81614048565b925061416960208501613e86565b9150604084013590509250925092565b805182526020810151602083015260408101516040830152606081015160608301525050565b80516001600160a01b03168252602080820151906141bf90840182613ece565b5060408181015190830152606090810151910152565b80516001600160a01b03168252602090810151910152565b80516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b8a81526001600160a01b038a811660208301528916604082015260608101889052861515608082015260a08101869052610280810161425b60c0830187614179565b61426961014083018661419f565b6142776101c08301856141d5565b6142856102008301846141ed565b9b9a5050505050505050505050565b6000806000606084860312156142a957600080fd5b6142b284613e86565b9250602084013591506142c760408501613e86565b90509250925092565b815181526020808301516102808301916142f4908401826001600160a01b03169052565b50604083015161430f60408401826001600160a01b03169052565b5060608301516060830152608083015161432d608084018215159052565b5060a083015160a083015260c083015161434a60c0840182614179565b5060e083015161435e61014084018261419f565b506101008301516143736101c08401826141d5565b506101208301516143886102008401826141ed565b5092915050565b60006020808352835180602085015260005b818110156143bd578581018301518582016040015282016143a1565b506000604082860101526040601f19601f8301168501019250505092915050565b634e487b7160e01b600052601160045260246000fd5b808201808211156108d1576108d16143de565b818103818111156108d1576108d16143de565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b03929092168252602082015260400190565b60006020828403121561445b57600080fd5b8151801515811461302657600080fd5b6001600160a01b0392831681529116602082015260400190565b80820281158282048414176108d1576108d16143de565b6000600182016144ae576144ae6143de565b5060010190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000826144f657634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561450d57600080fd5b5051919050565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220d25f358537997ae8171a8b21f2a548812a45b87cd8b9376ce9e8e3ed7c0f80ec64736f6c63430008170033

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

000000000000000000000000bbbbb8c4364ec2ce52c59d2ed3e56f307e529a940000000000000000000000007ad5935ea295c4e743e4f2f5b4cda951f41223c20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000bbbbb8c4364ec2ce52c59d2ed3e56f307e529a94

-----Decoded View---------------
Arg [0] : _owner (address): 0xbbbbb8C4364eC2ce52c59D2Ed3E56F307E529a94
Arg [1] : _depositToken (address): 0x7AD5935EA295c4E743e4f2f5B4CDA951f41223c2
Arg [2] : _positionDepositAmount (uint256): 1000000000000000000
Arg [3] : _feeRecipient (address): 0xbbbbb8C4364eC2ce52c59D2Ed3E56F307E529a94

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000bbbbb8c4364ec2ce52c59d2ed3e56f307e529a94
Arg [1] : 0000000000000000000000007ad5935ea295c4e743e4f2f5b4cda951f41223c2
Arg [2] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [3] : 000000000000000000000000bbbbb8c4364ec2ce52c59d2ed3e56f307e529a94


Block Transaction 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

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.