ETH Price: $3,969.57 (+4.42%)

Contract

0x2935CD347B79C319A6464fe3b1087170f142418C

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

ContractCreator

GENESIS at txn GENESIS_2935cd347b79c319a6464fe3b1087170f142418c

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw1288429552024-12-04 3:58:078 days ago1733284687IN
Lyra: ETH Liquidity Pool
0 ETH0.0000001542690.00010057
Withdraw1286507702024-11-29 17:11:5712 days ago1732900317IN
Lyra: ETH Liquidity Pool
0 ETH0.0000003582830.0010007
Un Signal Withdr...1284865152024-11-25 21:56:4716 days ago1732571807IN
Lyra: ETH Liquidity Pool
0 ETH0.000000455220.00010036
Withdraw1283149812024-11-21 22:38:5920 days ago1732228739IN
Lyra: ETH Liquidity Pool
0 ETH0.0000001466440.00010773
Withdraw1279149682024-11-12 16:25:1329 days ago1731428713IN
Lyra: ETH Liquidity Pool
0 ETH0.0000019492890.00079266
End Round1190922322024-04-22 10:54:01234 days ago1713783241IN
Lyra: ETH Liquidity Pool
0 ETH0.0007131573171.51002654
Withdraw1184650132024-04-07 22:26:43248 days ago1712528803IN
Lyra: ETH Liquidity Pool
0 ETH0.0000014992830.00711848
Withdraw1184650052024-04-07 22:26:27248 days ago1712528787IN
Lyra: ETH Liquidity Pool
0 ETH0.0000016724560.00710927
Withdraw1184423822024-04-07 9:52:21249 days ago1712483541IN
Lyra: ETH Liquidity Pool
0 ETH0.0000020810740.0091062
Withdraw1174530672024-03-15 12:15:11272 days ago1710504911IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015329620.00696158
Withdraw1174530642024-03-15 12:15:05272 days ago1710504905IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015378740.00698279
Withdraw1174530612024-03-15 12:14:59272 days ago1710504899IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015480580.00694601
Withdraw1174530592024-03-15 12:14:55272 days ago1710504895IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015546870.00697809
Withdraw1174530562024-03-15 12:14:49272 days ago1710504889IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015660630.00700057
Withdraw1174530492024-03-15 12:14:35272 days ago1710504875IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015519320.00701953
Withdraw1174530422024-03-15 12:14:21272 days ago1710504861IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015401540.00697902
Withdraw1174530342024-03-15 12:14:05272 days ago1710504845IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015345010.00695144
Withdraw1174530272024-03-15 12:13:51272 days ago1710504831IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015555970.0069564
Withdraw1174530202024-03-15 12:13:37272 days ago1710504817IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015270910.00697068
Withdraw1174530122024-03-15 12:13:21272 days ago1710504801IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015610080.00698231
Withdraw1174530042024-03-15 12:13:05272 days ago1710504785IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015578240.00696008
Withdraw1174529962024-03-15 12:12:49272 days ago1710504769IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015451560.00696698
Withdraw1174529892024-03-15 12:12:35272 days ago1710504755IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015486710.00696932
Withdraw1174529822024-03-15 12:12:21272 days ago1710504741IN
Lyra: ETH Liquidity Pool
0 ETH0.000001550290.00698079
Withdraw1174529752024-03-15 12:12:07272 days ago1710504727IN
Lyra: ETH Liquidity Pool
0 ETH0.0000015534580.00696524
View all transactions

Latest 5 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
1055399872023-06-13 17:52:31547 days ago1686678751
Lyra: ETH Liquidity Pool
0 ETH
1055399872023-06-13 17:52:31547 days ago1686678751
Lyra: ETH Liquidity Pool
0 ETH
1055399872023-06-13 17:52:31547 days ago1686678751
Lyra: ETH Liquidity Pool
0 ETH
1055399872023-06-13 17:52:31547 days ago1686678751
Lyra: ETH Liquidity Pool
0 ETH
1053055782023-06-08 7:38:53553 days ago1686209933
Lyra: ETH Liquidity Pool
0 ETH

Loading...
Loading

Contract Source Code Verified (Genesis Bytecode Match Only)

Contract Name:
LiquidityPool

Compiler Version
v0.7.6

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 14 : LiquidityPool.sol
//SPDX-License-Identifier: ISC
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

// Libraries
import "./synthetix/SafeDecimalMath.sol";

// Interfaces
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/IOptionMarket.sol";
import "./interfaces/ILiquidityCertificate.sol";
import "./interfaces/IPoolHedger.sol";
import "./interfaces/IShortCollateral.sol";

/**
 * @title LiquidityPool
 * @author Lyra
 * @dev Holds funds from LPs, which are used for the following purposes:
 * 1. Collateralizing options sold by the OptionMarket.
 * 2. Buying options from users.
 * 3. Delta hedging the LPs.
 * 4. Storing funds for expired in the money options.
 */
contract LiquidityPool is ILiquidityPool {
  using SafeMath for uint;
  using SafeDecimalMath for uint;

  ////
  // Constants
  ////
  ILyraGlobals internal globals;
  IOptionMarket internal optionMarket;
  ILiquidityCertificate internal liquidityCertificate;
  IShortCollateral internal shortCollateral;
  IPoolHedger internal poolHedger;
  IERC20 internal quoteAsset;
  IERC20 internal baseAsset;
  uint internal constant INITIAL_RATE = 1e18;

  ////
  // Variables
  ////
  mapping(uint => string) internal errorMessages;

  bool internal initialized = false;

  /// @dev Amount of collateral locked for outstanding calls and puts sold to users
  Collateral public override lockedCollateral;
  /**
   * @dev Total amount of quoteAsset held to pay out users who have locked/waited for their tokens to be burnable. As
   * well as keeping track of all settled option's usd value.
   */
  uint internal totalQuoteAmountReserved;
  /// @dev Total number of tokens that will be removed from the totalTokenSupply at the end of the round.
  uint internal tokensBurnableForRound;
  /// @dev Funds entering the pool in the next round.
  uint public override queuedQuoteFunds;
  /// @dev Total amount of tokens that represents the total amount of pool shares
  uint internal totalTokenSupply;
  /// @dev Counter for reentrancy guard.
  uint internal counter = 1;

  /**
   * @dev Mapping of timestamps to conversion rates of liquidity to tokens. To get the token value of a certificate;
   * `certificate.liquidity / expiryToTokenValue[certificate.enteredAt]`
   */
  mapping(uint => uint) public override expiryToTokenValue;

  constructor() {}

  /**
   * @dev Initialize the contract.
   *
   * @param _optionMarket OptionMarket address
   * @param _liquidityCertificate LiquidityCertificate address
   * @param _quoteAsset Quote Asset address
   * @param _poolHedger PoolHedger address
   */
  function init(
    ILyraGlobals _globals,
    IOptionMarket _optionMarket,
    ILiquidityCertificate _liquidityCertificate,
    IPoolHedger _poolHedger,
    IShortCollateral _shortCollateral,
    IERC20 _quoteAsset,
    IERC20 _baseAsset,
    string[] memory _errorMessages
  ) external {
    require(!initialized, "already initialized");
    globals = _globals;
    optionMarket = _optionMarket;
    liquidityCertificate = _liquidityCertificate;
    shortCollateral = _shortCollateral;
    poolHedger = _poolHedger;
    quoteAsset = _quoteAsset;
    baseAsset = _baseAsset;
    require(_errorMessages.length == uint(Error.Last), "error msg count");
    for (uint i = 0; i < _errorMessages.length; i++) {
      errorMessages[i] = _errorMessages[i];
    }
    initialized = true;
  }

  ////////////////////////////////////////////////////////////////
  // Dealing with providing liquidity and withdrawing liquidity //
  ////////////////////////////////////////////////////////////////

  /**
   * @dev Deposits liquidity to the pool. This assumes users have authorised access to the quote ERC20 token. Will add
   * any deposited amount to the queuedQuoteFunds until the next round begins.
   *
   * @param beneficiary The account that will receive the liquidity certificate.
   * @param amount The amount of quoteAsset to deposit.
   */
  function deposit(address beneficiary, uint amount) external override returns (uint) {
    // Assume we have the allowance to take the amount they are depositing
    queuedQuoteFunds = queuedQuoteFunds.add(amount);
    uint certificateId = liquidityCertificate.mint(beneficiary, amount, optionMarket.maxExpiryTimestamp());
    emit Deposit(beneficiary, certificateId, amount);
    _require(quoteAsset.transferFrom(msg.sender, address(this), amount), Error.QuoteTransferFailed);
    return certificateId;
  }

  /**
   * @notice Signals withdraw of liquidity from the pool.
   * @dev It is not possible to withdraw during a round, thus a user can signal to withdraw at the time the round ends.
   *
   * @param certificateId The id of the LiquidityCertificate.
   */
  function signalWithdrawal(uint certificateId) external override {
    ILiquidityCertificate.CertificateData memory certificateData = liquidityCertificate.certificateData(certificateId);
    uint maxExpiryTimestamp = optionMarket.maxExpiryTimestamp();

    _require(certificateData.burnableAt == 0, Error.AlreadySignalledWithdrawal);
    _require(
      certificateData.enteredAt != maxExpiryTimestamp && expiryToTokenValue[maxExpiryTimestamp] == 0,
      Error.SignallingBetweenRounds
    );

    if (certificateData.enteredAt == 0) {
      // Dividing by INITIAL_RATE is redundant as initial rate is 1 unit
      tokensBurnableForRound = tokensBurnableForRound.add(certificateData.liquidity);
    } else {
      tokensBurnableForRound = tokensBurnableForRound.add(
        certificateData.liquidity.divideDecimal(expiryToTokenValue[certificateData.enteredAt])
      );
    }

    liquidityCertificate.setBurnableAt(msg.sender, certificateId, maxExpiryTimestamp);

    emit WithdrawSignaled(certificateId, tokensBurnableForRound);
  }

  /**
   * @dev Undo a previously signalled withdraw. Certificate owner must have signalled withdraw to call this function,
   * and cannot unsignal if the token is already burnable or burnt.
   *
   * @param certificateId The id of the LiquidityCertificate.
   */
  function unSignalWithdrawal(uint certificateId) external override {
    ILiquidityCertificate.CertificateData memory certificateData = liquidityCertificate.certificateData(certificateId);

    // Cannot unsignal withdrawal if the token is burnable/hasn't signalled exit
    _require(certificateData.burnableAt != 0, Error.UnSignalMustSignalFirst);
    _require(expiryToTokenValue[certificateData.burnableAt] == 0, Error.UnSignalAlreadyBurnable);

    liquidityCertificate.setBurnableAt(msg.sender, certificateId, 0);

    if (certificateData.enteredAt == 0) {
      // Dividing by INITIAL_RATE is redundant as initial rate is 1 unit
      tokensBurnableForRound = tokensBurnableForRound.sub(certificateData.liquidity);
    } else {
      tokensBurnableForRound = tokensBurnableForRound.sub(
        certificateData.liquidity.divideDecimal(expiryToTokenValue[certificateData.enteredAt])
      );
    }

    emit WithdrawUnSignaled(certificateId, tokensBurnableForRound);
  }

  /**
   * @dev Withdraws liquidity from the pool.
   *
   * This requires tokens to have been locked until the round ending at the burnableAt timestamp has been ended.
   * This will burn the liquidityCertificates and have the quote asset equivalent at the time be reserved for the users.
   *
   * @param beneficiary The account that will receive the withdrawn funds.
   * @param certificateId The id of the LiquidityCertificate.
   */
  function withdraw(address beneficiary, uint certificateId) external override returns (uint value) {
    ILiquidityCertificate.CertificateData memory certificateData = liquidityCertificate.certificateData(certificateId);
    uint maxExpiryTimestamp = optionMarket.maxExpiryTimestamp();

    // We allow people to withdraw if their funds haven't entered the system
    if (certificateData.enteredAt == maxExpiryTimestamp) {
      queuedQuoteFunds = queuedQuoteFunds.sub(certificateData.liquidity);
      liquidityCertificate.burn(msg.sender, certificateId);
      emit Withdraw(beneficiary, certificateId, certificateData.liquidity, totalQuoteAmountReserved);
      _require(quoteAsset.transfer(beneficiary, certificateData.liquidity), Error.QuoteTransferFailed);
      return certificateData.liquidity;
    }

    uint enterValue = certificateData.enteredAt == 0 ? INITIAL_RATE : expiryToTokenValue[certificateData.enteredAt];

    // expiryToTokenValue will only be set if the previous round has ended, and the next has not started
    uint currentRoundValue = expiryToTokenValue[maxExpiryTimestamp];

    // If they haven't signaled withdrawal, and it is between rounds
    if (certificateData.burnableAt == 0 && currentRoundValue != 0) {
      uint tokenAmt = certificateData.liquidity.divideDecimal(enterValue);
      totalTokenSupply = totalTokenSupply.sub(tokenAmt);
      value = tokenAmt.multiplyDecimal(currentRoundValue);
      liquidityCertificate.burn(msg.sender, certificateId);
      emit Withdraw(beneficiary, certificateId, value, totalQuoteAmountReserved);
      _require(quoteAsset.transfer(beneficiary, value), Error.QuoteTransferFailed);
      return value;
    }

    uint exitValue = expiryToTokenValue[certificateData.burnableAt];

    _require(certificateData.burnableAt != 0 && exitValue != 0, Error.WithdrawNotBurnable);

    value = certificateData.liquidity.multiplyDecimal(exitValue).divideDecimal(enterValue);

    // We can allow a 0 expiry for options created before any boards exist
    liquidityCertificate.burn(msg.sender, certificateId);

    totalQuoteAmountReserved = totalQuoteAmountReserved.sub(value);
    emit Withdraw(beneficiary, certificateId, value, totalQuoteAmountReserved);
    _require(quoteAsset.transfer(beneficiary, value), Error.QuoteTransferFailed);
    return value;
  }

  //////////////////////////////////////////////
  // Dealing with locking and expiry rollover //
  //////////////////////////////////////////////

  /**
   * @dev Return Token value.
   *
   * This token price is only accurate within the period between rounds.
   */
  function tokenPriceQuote() public view override returns (uint) {
    ILyraGlobals.ExchangeGlobals memory exchangeGlobals =
      globals.getExchangeGlobals(address(optionMarket), ILyraGlobals.ExchangeType.ALL);

    if (totalTokenSupply == 0) {
      return INITIAL_RATE;
    }

    uint poolValue =
      getTotalPoolValueQuote(
        exchangeGlobals.spotPrice,
        poolHedger.getValueQuote(exchangeGlobals.short, exchangeGlobals.spotPrice)
      );
    return poolValue.divideDecimal(totalTokenSupply);
  }

  /**
   * @notice Ends a round.
   * @dev Should only be called after all boards have been liquidated.
   */
  function endRound() external override {
    // Round can only be ended if all boards have been liquidated, and can only be called once.
    uint maxExpiryTimestamp = optionMarket.maxExpiryTimestamp();
    // We must ensure all boards have been expired
    _require(optionMarket.getLiveBoards().length == 0, Error.EndRoundWithLiveBoards);
    // We can only end the round once
    _require(expiryToTokenValue[maxExpiryTimestamp] == 0, Error.EndRoundAlreadyEnded);
    // We want to make sure all base collateral has been exchanged
    _require(baseAsset.balanceOf(address(this)) == 0, Error.EndRoundMustExchangeBase);
    // We want to make sure there is no outstanding poolHedger balance. If there is collateral left in the poolHedger
    // it will not affect calculations.
    _require(poolHedger.getCurrentHedgedNetDelta() == 0, Error.EndRoundMustHedgeDelta);

    uint pricePerToken = tokenPriceQuote();

    // Store the value for the tokens that are burnable for this round
    expiryToTokenValue[maxExpiryTimestamp] = pricePerToken;

    // Reserve the amount of quote we need for the tokens that are burnable
    totalQuoteAmountReserved = totalQuoteAmountReserved.add(tokensBurnableForRound.multiplyDecimal(pricePerToken));
    emit QuoteReserved(tokensBurnableForRound.multiplyDecimal(pricePerToken), totalQuoteAmountReserved);

    totalTokenSupply = totalTokenSupply.sub(tokensBurnableForRound);
    emit RoundEnded(maxExpiryTimestamp, pricePerToken, totalQuoteAmountReserved, tokensBurnableForRound);
    tokensBurnableForRound = 0;
  }

  /**
   * @dev Starts a round. Can only be called by optionMarket contract when adding a board.
   *
   * @param lastMaxExpiryTimestamp The time at which the previous round ended.
   * @param newMaxExpiryTimestamp The time which funds will be locked until.
   */
  function startRound(uint lastMaxExpiryTimestamp, uint newMaxExpiryTimestamp) external override onlyOptionMarket {
    // As the value is never reset, this is when the first board is added
    if (lastMaxExpiryTimestamp == 0) {
      totalTokenSupply = queuedQuoteFunds;
    } else {
      _require(expiryToTokenValue[lastMaxExpiryTimestamp] != 0, Error.StartRoundMustEndRound);
      totalTokenSupply = totalTokenSupply.add(
        queuedQuoteFunds.divideDecimal(expiryToTokenValue[lastMaxExpiryTimestamp])
      );
    }
    queuedQuoteFunds = 0;

    emit RoundStarted(
      lastMaxExpiryTimestamp,
      newMaxExpiryTimestamp,
      totalTokenSupply,
      lastMaxExpiryTimestamp == 0 ? SafeDecimalMath.UNIT : expiryToTokenValue[lastMaxExpiryTimestamp]
    );
  }

  /////////////////////////////////////////
  // Dealing with collateral for options //
  /////////////////////////////////////////

  /**
   * @dev external override function that will bring the base balance of this contract to match locked.base. This cannot be done
   * in the same transaction as locking the base, as exchanging on synthetix is too costly gas-wise.
   */
  function exchangeBase() external override reentrancyGuard {
    uint currentBaseBalance = baseAsset.balanceOf(address(this));

    // Add this additional check to prevent any soft locks at round end, as the base balance must be 0 to end the round.
    if (optionMarket.getLiveBoards().length == 0) {
      lockedCollateral.base = 0;
    }

    if (currentBaseBalance > lockedCollateral.base) {
      // Sell excess baseAsset
      ILyraGlobals.ExchangeGlobals memory exchangeGlobals =
        globals.getExchangeGlobals(address(optionMarket), ILyraGlobals.ExchangeType.BASE_QUOTE);
      uint amount = currentBaseBalance - lockedCollateral.base;
      uint quoteReceived =
        exchangeGlobals.synthetix.exchange(exchangeGlobals.baseKey, amount, exchangeGlobals.quoteKey);
      _require(quoteReceived > 0, Error.ReceivedZeroFromBaseQuoteExchange);
      emit BaseSold(msg.sender, amount, quoteReceived);
    } else if (lockedCollateral.base > currentBaseBalance) {
      // Buy required amount of baseAsset
      ILyraGlobals.ExchangeGlobals memory exchangeGlobals =
        globals.getExchangeGlobals(address(optionMarket), ILyraGlobals.ExchangeType.QUOTE_BASE);
      uint quoteToSpend =
        (lockedCollateral.base - currentBaseBalance)
          .divideDecimalRound(SafeDecimalMath.UNIT.sub(exchangeGlobals.quoteBaseFeeRate))
          .multiplyDecimalRound(exchangeGlobals.spotPrice);
      uint totalQuoteAvailable =
        quoteAsset.balanceOf(address(this)).sub(totalQuoteAmountReserved).sub(lockedCollateral.quote).sub(
          queuedQuoteFunds
        );
      // We want to always buy as much collateral as we can, even if it dips into the delta hedging portion.
      // But we cannot compromise funds that aren't useable by the pool.
      quoteToSpend = quoteToSpend > totalQuoteAvailable ? totalQuoteAvailable : quoteToSpend;
      uint amtReceived =
        exchangeGlobals.synthetix.exchange(exchangeGlobals.quoteKey, quoteToSpend, exchangeGlobals.baseKey);
      _require(amtReceived > 0, Error.ReceivedZeroFromQuoteBaseExchange);
      emit BasePurchased(msg.sender, quoteToSpend, amtReceived);
    }
  }

  /**
   * @notice Locks quote when the system sells a put option.
   *
   * @param amount The amount of quote to lock.
   * @param freeCollatLiq The amount of free collateral that can be locked.
   */
  function lockQuote(uint amount, uint freeCollatLiq) external override onlyOptionMarket {
    _require(amount <= freeCollatLiq, Error.LockingMoreQuoteThanIsFree);
    lockedCollateral.quote = lockedCollateral.quote.add(amount);
    emit QuoteLocked(amount, lockedCollateral.quote);
  }

  /**
   * @notice Purchases and locks base when the system sells a call option.
   *
   * @param amount The amount of baseAsset to purchase and lock.
   * @param exchangeGlobals The exchangeGlobals.
   * @param liquidity Free and used liquidity amounts.
   */
  function lockBase(
    uint amount,
    ILyraGlobals.ExchangeGlobals memory exchangeGlobals,
    Liquidity memory liquidity
  ) external override onlyOptionMarket {
    uint currentBaseBal = baseAsset.balanceOf(address(this));

    uint desiredBase;
    uint availableQuote = liquidity.freeCollatLiquidity;

    if (lockedCollateral.base >= currentBaseBal) {
      uint outstanding = lockedCollateral.base - currentBaseBal;
      // We need to ignore any base we haven't purchased yet from our availableQuote
      availableQuote = availableQuote.add(outstanding.multiplyDecimal(exchangeGlobals.spotPrice));
      // But we want to make sure we will have enough quote to cover the debt owed on top of new base we want to lock
      desiredBase = amount.add(outstanding);
    } else {
      // We actually need to buy less, or none, if we already have excess balance
      uint excess = currentBaseBal - lockedCollateral.base;
      if (excess >= amount) {
        desiredBase = 0;
      } else {
        desiredBase = amount.sub(excess);
      }
    }
    uint quoteToSpend =
      desiredBase.divideDecimalRound(SafeDecimalMath.UNIT.sub(exchangeGlobals.quoteBaseFeeRate)).multiplyDecimalRound(
        exchangeGlobals.spotPrice
      );

    _require(availableQuote >= quoteToSpend, Error.LockingMoreBaseThanCanBeExchanged);

    lockedCollateral.base = lockedCollateral.base.add(amount);
    emit BaseLocked(amount, lockedCollateral.base);
  }

  /**
   * @notice Frees quote when the system buys back a put from the user.
   *
   * @param amount The amount of quote to free.
   */
  function freeQuoteCollateral(uint amount) external override onlyOptionMarket {
    _freeQuoteCollateral(amount);
  }

  /**
   * @notice Frees quote when the system buys back a put from the user.
   *
   * @param amount The amount of quote to free.
   */
  function _freeQuoteCollateral(uint amount) internal {
    // Handle rounding errors by returning the full amount when the requested amount is greater
    if (amount > lockedCollateral.quote) {
      amount = lockedCollateral.quote;
    }
    lockedCollateral.quote = lockedCollateral.quote.sub(amount);
    emit QuoteFreed(amount, lockedCollateral.quote);
  }

  /**
   * @notice Sells base and frees the proceeds of the sale.
   *
   * @param amountBase The amount of base to sell.
   */
  function freeBase(uint amountBase) external override onlyOptionMarket {
    _require(amountBase <= lockedCollateral.base, Error.FreeingMoreBaseThanLocked);
    lockedCollateral.base = lockedCollateral.base.sub(amountBase);
    emit BaseFreed(amountBase, lockedCollateral.base);
  }

  /**
   * @notice Sends the premium to a user who is selling an option to the pool.
   * @dev The caller must be the OptionMarket.
   *
   * @param recipient The address of the recipient.
   * @param amount The amount to transfer.
   * @param freeCollatLiq The amount of free collateral liquidity.
   */
  function sendPremium(
    address recipient,
    uint amount,
    uint freeCollatLiq
  ) external override onlyOptionMarket reentrancyGuard {
    _require(freeCollatLiq >= amount, Error.SendPremiumNotEnoughCollateral);
    _require(quoteAsset.transfer(recipient, amount), Error.QuoteTransferFailed);

    emit CollateralQuoteTransferred(recipient, amount);
  }

  //////////////////////////////////////////
  // Dealing with expired option premiums //
  //////////////////////////////////////////

  /**
   * @notice Manages collateral at the time of board liquidation, also converting base sent here from the OptionMarket.
   *
   * @param amountQuoteFreed Total amount of base to convert to quote, including profits from short calls.
   * @param amountQuoteReserved Total amount of base to convert to quote, including profits from short calls.
   * @param amountBaseFreed Total amount of collateral to liquidate.
   */
  function boardLiquidation(
    uint amountQuoteFreed,
    uint amountQuoteReserved,
    uint amountBaseFreed
  ) external override onlyOptionMarket {
    _freeQuoteCollateral(amountQuoteFreed);

    totalQuoteAmountReserved = totalQuoteAmountReserved.add(amountQuoteReserved);
    emit QuoteReserved(amountQuoteReserved, totalQuoteAmountReserved);

    lockedCollateral.base = lockedCollateral.base.sub(amountBaseFreed);
    emit BaseFreed(amountBaseFreed, lockedCollateral.base);
  }

  /**
   * @dev Transfers reserved quote. Sends `amount` of reserved quoteAsset to `user`.
   *
   * Requirements:
   *
   * - the caller must be `OptionMarket`.
   *
   * @param user The address of the user to send the quote.
   * @param amount The amount of quote to send.
   */
  function sendReservedQuote(address user, uint amount) external override onlyShortCollateral reentrancyGuard {
    // Should never happen, but added to prevent any potential rounding errors
    if (amount > totalQuoteAmountReserved) {
      amount = totalQuoteAmountReserved;
    }
    totalQuoteAmountReserved = totalQuoteAmountReserved.sub(amount);
    _require(quoteAsset.transfer(user, amount), Error.QuoteTransferFailed);

    emit ReservedQuoteSent(user, amount, totalQuoteAmountReserved);
  }

  ////////////////////////////
  // Getting Pool Liquidity //
  ////////////////////////////

  /**
   * @notice Returns the total pool value in quoteAsset.
   *
   * @param basePrice The price of the baseAsset.
   * @param usedDeltaLiquidity The amout of delta liquidity that has been used for hedging.
   */
  function getTotalPoolValueQuote(uint basePrice, uint usedDeltaLiquidity) public view override returns (uint) {
    return
      quoteAsset
        .balanceOf(address(this))
        .add(baseAsset.balanceOf(address(this)).multiplyDecimal(basePrice))
        .add(usedDeltaLiquidity)
        .sub(totalQuoteAmountReserved)
        .sub(queuedQuoteFunds);
  }

  /**
   * @notice Returns the used and free amounts for collateral and delta liquidity.
   *
   * @param basePrice The price of the base asset.
   * @param short The address of the short contract.
   */
  function getLiquidity(uint basePrice, ICollateralShort short) public view override returns (Liquidity memory) {
    Liquidity memory liquidity;

    liquidity.usedDeltaLiquidity = poolHedger.getValueQuote(short, basePrice);
    liquidity.usedCollatLiquidity = lockedCollateral.quote.add(lockedCollateral.base.multiplyDecimal(basePrice));

    uint totalLiquidity = getTotalPoolValueQuote(basePrice, liquidity.usedDeltaLiquidity);

    uint collatPortion = (totalLiquidity * 2) / 3;
    uint deltaPortion = totalLiquidity.sub(collatPortion);

    if (liquidity.usedCollatLiquidity > collatPortion) {
      collatPortion = liquidity.usedCollatLiquidity;
      deltaPortion = totalLiquidity.sub(collatPortion);
    } else if (liquidity.usedDeltaLiquidity > deltaPortion) {
      deltaPortion = liquidity.usedDeltaLiquidity;
      collatPortion = totalLiquidity.sub(deltaPortion);
    }

    liquidity.freeDeltaLiquidity = deltaPortion.sub(liquidity.usedDeltaLiquidity);
    liquidity.freeCollatLiquidity = collatPortion.sub(liquidity.usedCollatLiquidity);

    return liquidity;
  }

  //////////
  // Misc //
  //////////

  /**
   * @notice Sends quoteAsset to the PoolHedger.
   * @dev This function will transfer whatever free delta liquidity is available.
   * The hedger must determine what to do with the amount received.
   *
   * @param exchangeGlobals The exchangeGlobals.
   * @param amount The amount requested by the PoolHedger.
   */
  function transferQuoteToHedge(ILyraGlobals.ExchangeGlobals memory exchangeGlobals, uint amount)
    external
    override
    onlyPoolHedger
    reentrancyGuard
    returns (uint)
  {
    Liquidity memory liquidity = getLiquidity(exchangeGlobals.spotPrice, exchangeGlobals.short);

    uint available = liquidity.freeDeltaLiquidity;
    if (available < amount) {
      amount = available;
    }
    _require(quoteAsset.transfer(address(poolHedger), amount), Error.QuoteTransferFailed);

    emit DeltaQuoteTransferredToPoolHedger(amount);

    return amount;
  }

  function _require(bool pass, Error error) internal view {
    require(pass, errorMessages[uint(error)]);
  }

  ///////////////
  // Modifiers //
  ///////////////

  modifier onlyPoolHedger virtual {
    _require(msg.sender == address(poolHedger), Error.OnlyPoolHedger);
    _;
  }

  modifier onlyOptionMarket virtual {
    _require(msg.sender == address(optionMarket), Error.OnlyOptionMarket);
    _;
  }

  modifier onlyShortCollateral virtual {
    _require(msg.sender == address(shortCollateral), Error.OnlyShortCollateral);
    _;
  }

  modifier reentrancyGuard virtual {
    counter = counter.add(1); // counter adds 1 to the existing 1 so becomes 2
    uint guard = counter; // assigns 2 to the "guard" variable
    _;
    _require(guard == counter, Error.ReentrancyDetected);
  }

  /**
   * @dev Emitted when liquidity is deposited.
   */
  event Deposit(address indexed beneficiary, uint indexed certificateId, uint amount);
  /**
   * @dev Emitted when withdrawal is signaled.
   */
  event WithdrawSignaled(uint indexed certificateId, uint tokensBurnableForRound);
  /**
   * @dev Emitted when a withdrawal is unsignaled.
   */
  event WithdrawUnSignaled(uint indexed certificateId, uint tokensBurnableForRound);
  /**
   * @dev Emitted when liquidity is withdrawn.
   */
  event Withdraw(address indexed beneficiary, uint indexed certificateId, uint value, uint totalQuoteAmountReserved);
  /**
   * @dev Emitted when a round ends.
   */
  event RoundEnded(
    uint indexed maxExpiryTimestamp,
    uint pricePerToken,
    uint totalQuoteAmountReserved,
    uint tokensBurnableForRound
  );
  /**
   * @dev Emitted when a round starts.
   */
  event RoundStarted(
    uint indexed lastMaxExpiryTimestamp,
    uint indexed newMaxExpiryTimestamp,
    uint totalTokenSupply,
    uint tokenValue
  );
  /**
   * @dev Emitted when quote is locked.
   */
  event QuoteLocked(uint quoteLocked, uint lockedCollateralQuote);
  /**
   * @dev Emitted when base is locked.
   */
  event BaseLocked(uint baseLocked, uint lockedCollateralBase);
  /**
   * @dev Emitted when quote is freed.
   */
  event QuoteFreed(uint quoteFreed, uint lockedCollateralQuote);
  /**
   * @dev Emitted when base is freed.
   */
  event BaseFreed(uint baseFreed, uint lockedCollateralBase);
  /**
   * @dev Emitted when base is purchased.
   */
  event BasePurchased(address indexed caller, uint quoteSpent, uint amountPurchased);
  /**
   * @dev Emitted when base is sold.
   */
  event BaseSold(address indexed caller, uint amountSold, uint quoteReceived);
  /**
   * @dev Emitted when collateral is liquidated. This combines LP profit from short calls and freeing base collateral
   */
  event CollateralLiquidated(
    uint totalAmountToLiquidate,
    uint baseFreed,
    uint quoteReceived,
    uint lockedCollateralBase
  );
  /**
   * @dev Emitted when quote is reserved.
   */
  event QuoteReserved(uint amountQuoteReserved, uint totalQuoteAmountReserved);
  /**
   * @dev Emitted when reserved quote is sent.
   */
  event ReservedQuoteSent(address indexed user, uint amount, uint totalQuoteAmountReserved);
  /**
   * @dev Emitted when collatQuote is transferred.
   */
  event CollateralQuoteTransferred(address indexed recipient, uint amount);
  /**
   * @dev Emitted when quote is transferred to hedge.
   */
  event DeltaQuoteTransferredToPoolHedger(uint amount);
}

File 2 of 14 : SafeDecimalMath.sol
//SPDX-License-Identifier: MIT
//
//Copyright (c) 2019 Synthetix
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.

pragma solidity ^0.7.6;

// Libraries
import "@openzeppelin/contracts/math/SafeMath.sol";

// https://docs.synthetix.io/contracts/source/libraries/SafeDecimalMath/
library SafeDecimalMath {
  using SafeMath for uint;

  /* Number of decimal places in the representations. */
  uint8 public constant decimals = 18;
  uint8 public constant highPrecisionDecimals = 27;

  /* The number representing 1.0. */
  uint public constant UNIT = 10**uint(decimals);

  /* The number representing 1.0 for higher fidelity numbers. */
  uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals);
  uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals);

  /**
   * @return Provides an interface to UNIT.
   */
  function unit() external pure returns (uint) {
    return UNIT;
  }

  /**
   * @return Provides an interface to PRECISE_UNIT.
   */
  function preciseUnit() external pure returns (uint) {
    return PRECISE_UNIT;
  }

  /**
   * @return The result of multiplying x and y, interpreting the operands as fixed-point
   * decimals.
   *
   * @dev A unit factor is divided out after the product of x and y is evaluated,
   * so that product must be less than 2**256. As this is an integer division,
   * the internal division always rounds down. This helps save on gas. Rounding
   * is more expensive on gas.
   */
  function multiplyDecimal(uint x, uint y) internal pure returns (uint) {
    /* Divide by UNIT to remove the extra factor introduced by the product. */
    return x.mul(y) / UNIT;
  }

  /**
   * @return The result of safely multiplying x and y, interpreting the operands
   * as fixed-point decimals of the specified precision unit.
   *
   * @dev The operands should be in the form of a the specified unit factor which will be
   * divided out after the product of x and y is evaluated, so that product must be
   * less than 2**256.
   *
   * Unlike multiplyDecimal, this function rounds the result to the nearest increment.
   * Rounding is useful when you need to retain fidelity for small decimal numbers
   * (eg. small fractions or percentages).
   */
  function _multiplyDecimalRound(
    uint x,
    uint y,
    uint precisionUnit
  ) private pure returns (uint) {
    /* Divide by UNIT to remove the extra factor introduced by the product. */
    uint quotientTimesTen = x.mul(y) / (precisionUnit / 10);

    if (quotientTimesTen % 10 >= 5) {
      quotientTimesTen += 10;
    }

    return quotientTimesTen / 10;
  }

  /**
   * @return The result of safely multiplying x and y, interpreting the operands
   * as fixed-point decimals of a precise unit.
   *
   * @dev The operands should be in the precise unit factor which will be
   * divided out after the product of x and y is evaluated, so that product must be
   * less than 2**256.
   *
   * Unlike multiplyDecimal, this function rounds the result to the nearest increment.
   * Rounding is useful when you need to retain fidelity for small decimal numbers
   * (eg. small fractions or percentages).
   */
  function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) {
    return _multiplyDecimalRound(x, y, PRECISE_UNIT);
  }

  /**
   * @return The result of safely multiplying x and y, interpreting the operands
   * as fixed-point decimals of a standard unit.
   *
   * @dev The operands should be in the standard unit factor which will be
   * divided out after the product of x and y is evaluated, so that product must be
   * less than 2**256.
   *
   * Unlike multiplyDecimal, this function rounds the result to the nearest increment.
   * Rounding is useful when you need to retain fidelity for small decimal numbers
   * (eg. small fractions or percentages).
   */
  function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) {
    return _multiplyDecimalRound(x, y, UNIT);
  }

  /**
   * @return The result of safely dividing x and y. The return value is a high
   * precision decimal.
   *
   * @dev y is divided after the product of x and the standard precision unit
   * is evaluated, so the product of x and UNIT must be less than 2**256. As
   * this is an integer division, the result is always rounded down.
   * This helps save on gas. Rounding is more expensive on gas.
   */
  function divideDecimal(uint x, uint y) internal pure returns (uint) {
    /* Reintroduce the UNIT factor that will be divided out by y. */
    return x.mul(UNIT).div(y);
  }

  /**
   * @return The result of safely dividing x and y. The return value is as a rounded
   * decimal in the precision unit specified in the parameter.
   *
   * @dev y is divided after the product of x and the specified precision unit
   * is evaluated, so the product of x and the specified precision unit must
   * be less than 2**256. The result is rounded to the nearest increment.
   */
  function _divideDecimalRound(
    uint x,
    uint y,
    uint precisionUnit
  ) private pure returns (uint) {
    uint resultTimesTen = x.mul(precisionUnit * 10).div(y);

    if (resultTimesTen % 10 >= 5) {
      resultTimesTen += 10;
    }

    return resultTimesTen / 10;
  }

  /**
   * @return The result of safely dividing x and y. The return value is as a rounded
   * standard precision decimal.
   *
   * @dev y is divided after the product of x and the standard precision unit
   * is evaluated, so the product of x and the standard precision unit must
   * be less than 2**256. The result is rounded to the nearest increment.
   */
  function divideDecimalRound(uint x, uint y) internal pure returns (uint) {
    return _divideDecimalRound(x, y, UNIT);
  }

  /**
   * @return The result of safely dividing x and y. The return value is as a rounded
   * high precision decimal.
   *
   * @dev y is divided after the product of x and the high precision unit
   * is evaluated, so the product of x and the high precision unit must
   * be less than 2**256. The result is rounded to the nearest increment.
   */
  function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) {
    return _divideDecimalRound(x, y, PRECISE_UNIT);
  }

  /**
   * @dev Convert a standard decimal representation to a high precision one.
   */
  function decimalToPreciseDecimal(uint i) internal pure returns (uint) {
    return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR);
  }

  /**
   * @dev Convert a high precision decimal to a standard decimal representation.
   */
  function preciseDecimalToDecimal(uint i) internal pure returns (uint) {
    uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10);

    if (quotientTimesTen % 10 >= 5) {
      quotientTimesTen += 10;
    }

    return quotientTimesTen / 10;
  }
}

File 3 of 14 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 4 of 14 : IOptionMarket.sol
//SPDX-License-Identifier: ISC
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "./ILyraGlobals.sol";
import "./ILiquidityPool.sol";

interface IOptionMarket {
  struct OptionListing {
    uint id;
    uint strike;
    uint skew;
    uint longCall;
    uint shortCall;
    uint longPut;
    uint shortPut;
    uint boardId;
  }

  struct OptionBoard {
    uint id;
    uint expiry;
    uint iv;
    bool frozen;
    uint[] listingIds;
  }

  struct Trade {
    bool isBuy;
    uint amount;
    uint vol;
    uint expiry;
    ILiquidityPool.Liquidity liquidity;
  }

  enum TradeType {LONG_CALL, SHORT_CALL, LONG_PUT, SHORT_PUT}

  enum Error {
    TransferOwnerToZero,
    InvalidBoardId,
    InvalidBoardIdOrNotFrozen,
    InvalidListingIdOrNotFrozen,
    StrikeSkewLengthMismatch,
    BoardMaxExpiryReached,
    CannotStartNewRoundWhenBoardsExist,
    ZeroAmountOrInvalidTradeType,
    BoardFrozenOrTradingCutoffReached,
    QuoteTransferFailed,
    BaseTransferFailed,
    BoardNotExpired,
    BoardAlreadyLiquidated,
    OnlyOwner,
    Last
  }

  function maxExpiryTimestamp() external view returns (uint);

  function optionBoards(uint)
    external
    view
    returns (
      uint id,
      uint expiry,
      uint iv,
      bool frozen
    );

  function optionListings(uint)
    external
    view
    returns (
      uint id,
      uint strike,
      uint skew,
      uint longCall,
      uint shortCall,
      uint longPut,
      uint shortPut,
      uint boardId
    );

  function boardToPriceAtExpiry(uint) external view returns (uint);

  function listingToBaseReturnedRatio(uint) external view returns (uint);

  function transferOwnership(address newOwner) external;

  function setBoardFrozen(uint boardId, bool frozen) external;

  function setBoardBaseIv(uint boardId, uint baseIv) external;

  function setListingSkew(uint listingId, uint skew) external;

  function createOptionBoard(
    uint expiry,
    uint baseIV,
    uint[] memory strikes,
    uint[] memory skews
  ) external returns (uint);

  function addListingToBoard(
    uint boardId,
    uint strike,
    uint skew
  ) external;

  function getLiveBoards() external view returns (uint[] memory _liveBoards);

  function getBoardListings(uint boardId) external view returns (uint[] memory);

  function openPosition(
    uint _listingId,
    TradeType tradeType,
    uint amount
  ) external returns (uint totalCost);

  function closePosition(
    uint _listingId,
    TradeType tradeType,
    uint amount
  ) external returns (uint totalCost);

  function liquidateExpiredBoard(uint boardId) external;

  function settleOptions(uint listingId, TradeType tradeType) external;
}

File 5 of 14 : ILiquidityCertificate.sol
//SPDX-License-Identifier: ISC
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

interface ILiquidityCertificate {
  struct CertificateData {
    uint liquidity;
    uint enteredAt;
    uint burnableAt;
  }

  function MIN_LIQUIDITY() external view returns (uint);

  function liquidityPool() external view returns (address);

  function certificates(address owner) external view returns (uint[] memory);

  function liquidity(uint certificateId) external view returns (uint);

  function enteredAt(uint certificateId) external view returns (uint);

  function burnableAt(uint certificateId) external view returns (uint);

  function certificateData(uint certificateId) external view returns (CertificateData memory);

  function mint(
    address owner,
    uint liquidityAmount,
    uint expiryAtCreation
  ) external returns (uint);

  function setBurnableAt(
    address spender,
    uint certificateId,
    uint timestamp
  ) external;

  function burn(address spender, uint certificateId) external;

  function split(uint certificateId, uint percentageSplit) external returns (uint);
}

File 6 of 14 : IPoolHedger.sol
//SPDX-License-Identifier: ISC
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "./ICollateralShort.sol";

interface IPoolHedger {
  function shortingInitialized() external view returns (bool);

  function shortId() external view returns (uint);

  function shortBuffer() external view returns (uint);

  function lastInteraction() external view returns (uint);

  function interactionDelay() external view returns (uint);

  function setShortBuffer(uint newShortBuffer) external;

  function setInteractionDelay(uint newInteractionDelay) external;

  function initShort() external;

  function reopenShort() external;

  function hedgeDelta() external;

  function getShortPosition(ICollateralShort short) external view returns (uint shortBalance, uint collateral);

  function getCurrentHedgedNetDelta() external view returns (int);

  function getValueQuote(ICollateralShort short, uint spotPrice) external view returns (uint value);
}

File 7 of 14 : IShortCollateral.sol
//SPDX-License-Identifier: ISC
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "./IOptionMarket.sol";

interface IShortCollateral {
  function sendQuoteCollateral(address recipient, uint amount) external;

  function sendBaseCollateral(address recipient, uint amount) external;

  function sendToLP(uint amountBase, uint amountQuote) external;

  function processSettle(
    uint listingId,
    address receiver,
    IOptionMarket.TradeType tradeType,
    uint amount,
    uint strike,
    uint priceAtExpiry,
    uint listingToShortCallEthReturned
  ) external;
}

File 8 of 14 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 9 of 14 : ILyraGlobals.sol
//SPDX-License-Identifier: ISC
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "./ICollateralShort.sol";
import "./IExchangeRates.sol";
import "./IExchanger.sol";
import "./ISynthetix.sol";

interface ILyraGlobals {
  enum ExchangeType {BASE_QUOTE, QUOTE_BASE, ALL}

  /**
   * @dev Structs to help reduce the number of calls between other contracts and this one
   * Grouped in usage for a particular contract/use case
   */
  struct ExchangeGlobals {
    uint spotPrice;
    bytes32 quoteKey;
    bytes32 baseKey;
    ISynthetix synthetix;
    ICollateralShort short;
    uint quoteBaseFeeRate;
    uint baseQuoteFeeRate;
  }

  struct GreekCacheGlobals {
    int rateAndCarry;
    uint spotPrice;
  }

  struct PricingGlobals {
    uint optionPriceFeeCoefficient;
    uint spotPriceFeeCoefficient;
    uint vegaFeeCoefficient;
    uint vegaNormFactor;
    uint standardSize;
    uint skewAdjustmentFactor;
    int rateAndCarry;
    int minDelta;
    uint volatilityCutoff;
    uint spotPrice;
  }

  function synthetix() external view returns (ISynthetix);

  function exchanger() external view returns (IExchanger);

  function exchangeRates() external view returns (IExchangeRates);

  function collateralShort() external view returns (ICollateralShort);

  function isPaused() external view returns (bool);

  function tradingCutoff(address) external view returns (uint);

  function optionPriceFeeCoefficient(address) external view returns (uint);

  function spotPriceFeeCoefficient(address) external view returns (uint);

  function vegaFeeCoefficient(address) external view returns (uint);

  function vegaNormFactor(address) external view returns (uint);

  function standardSize(address) external view returns (uint);

  function skewAdjustmentFactor(address) external view returns (uint);

  function rateAndCarry(address) external view returns (int);

  function minDelta(address) external view returns (int);

  function volatilityCutoff(address) external view returns (uint);

  function quoteKey(address) external view returns (bytes32);

  function baseKey(address) external view returns (bytes32);

  function setGlobals(
    ISynthetix _synthetix,
    IExchanger _exchanger,
    IExchangeRates _exchangeRates,
    ICollateralShort _collateralShort
  ) external;

  function setGlobalsForContract(
    address _contractAddress,
    uint _tradingCutoff,
    PricingGlobals memory pricingGlobals,
    bytes32 _quoteKey,
    bytes32 _baseKey
  ) external;

  function setPaused(bool _isPaused) external;

  function setTradingCutoff(address _contractAddress, uint _tradingCutoff) external;

  function setOptionPriceFeeCoefficient(address _contractAddress, uint _optionPriceFeeCoefficient) external;

  function setSpotPriceFeeCoefficient(address _contractAddress, uint _spotPriceFeeCoefficient) external;

  function setVegaFeeCoefficient(address _contractAddress, uint _vegaFeeCoefficient) external;

  function setVegaNormFactor(address _contractAddress, uint _vegaNormFactor) external;

  function setStandardSize(address _contractAddress, uint _standardSize) external;

  function setSkewAdjustmentFactor(address _contractAddress, uint _skewAdjustmentFactor) external;

  function setRateAndCarry(address _contractAddress, int _rateAndCarry) external;

  function setMinDelta(address _contractAddress, int _minDelta) external;

  function setVolatilityCutoff(address _contractAddress, uint _volatilityCutoff) external;

  function setQuoteKey(address _contractAddress, bytes32 _quoteKey) external;

  function setBaseKey(address _contractAddress, bytes32 _baseKey) external;

  function getSpotPriceForMarket(address _contractAddress) external view returns (uint);

  function getSpotPrice(bytes32 to) external view returns (uint);

  function getPricingGlobals(address _contractAddress) external view returns (PricingGlobals memory);

  function getGreekCacheGlobals(address _contractAddress) external view returns (GreekCacheGlobals memory);

  function getExchangeGlobals(address _contractAddress, ExchangeType exchangeType)
    external
    view
    returns (ExchangeGlobals memory exchangeGlobals);

  function getGlobalsForOptionTrade(address _contractAddress, bool isBuy)
    external
    view
    returns (
      PricingGlobals memory pricingGlobals,
      ExchangeGlobals memory exchangeGlobals,
      uint tradeCutoff
    );
}

File 10 of 14 : ILiquidityPool.sol
//SPDX-License-Identifier: ISC
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "./ILyraGlobals.sol";

interface ILiquidityPool {
  struct Collateral {
    uint quote;
    uint base;
  }

  /// @dev These are all in quoteAsset amounts.
  struct Liquidity {
    uint freeCollatLiquidity;
    uint usedCollatLiquidity;
    uint freeDeltaLiquidity;
    uint usedDeltaLiquidity;
  }

  enum Error {
    QuoteTransferFailed,
    AlreadySignalledWithdrawal,
    SignallingBetweenRounds,
    UnSignalMustSignalFirst,
    UnSignalAlreadyBurnable,
    WithdrawNotBurnable,
    EndRoundWithLiveBoards,
    EndRoundAlreadyEnded,
    EndRoundMustExchangeBase,
    EndRoundMustHedgeDelta,
    StartRoundMustEndRound,
    ReceivedZeroFromBaseQuoteExchange,
    ReceivedZeroFromQuoteBaseExchange,
    LockingMoreQuoteThanIsFree,
    LockingMoreBaseThanCanBeExchanged,
    FreeingMoreBaseThanLocked,
    SendPremiumNotEnoughCollateral,
    OnlyPoolHedger,
    OnlyOptionMarket,
    OnlyShortCollateral,
    ReentrancyDetected,
    Last
  }

  function lockedCollateral() external view returns (uint, uint);

  function queuedQuoteFunds() external view returns (uint);

  function expiryToTokenValue(uint) external view returns (uint);

  function deposit(address beneficiary, uint amount) external returns (uint);

  function signalWithdrawal(uint certificateId) external;

  function unSignalWithdrawal(uint certificateId) external;

  function withdraw(address beneficiary, uint certificateId) external returns (uint value);

  function tokenPriceQuote() external view returns (uint);

  function endRound() external;

  function startRound(uint lastMaxExpiryTimestamp, uint newMaxExpiryTimestamp) external;

  function exchangeBase() external;

  function lockQuote(uint amount, uint freeCollatLiq) external;

  function lockBase(
    uint amount,
    ILyraGlobals.ExchangeGlobals memory exchangeGlobals,
    Liquidity memory liquidity
  ) external;

  function freeQuoteCollateral(uint amount) external;

  function freeBase(uint amountBase) external;

  function sendPremium(
    address recipient,
    uint amount,
    uint freeCollatLiq
  ) external;

  function boardLiquidation(
    uint amountQuoteFreed,
    uint amountQuoteReserved,
    uint amountBaseFreed
  ) external;

  function sendReservedQuote(address user, uint amount) external;

  function getTotalPoolValueQuote(uint basePrice, uint usedDeltaLiquidity) external view returns (uint);

  function getLiquidity(uint basePrice, ICollateralShort short) external view returns (Liquidity memory);

  function transferQuoteToHedge(ILyraGlobals.ExchangeGlobals memory exchangeGlobals, uint amount)
    external
    returns (uint);
}

File 11 of 14 : ICollateralShort.sol
//SPDX-License-Identifier: ISC
pragma solidity >=0.7.6;
pragma experimental ABIEncoderV2;

interface ICollateralShort {
  struct Loan {
    // ID for the loan
    uint id;
    //  Account that created the loan
    address account;
    //  Amount of collateral deposited
    uint collateral;
    // The synth that was borrowed
    bytes32 currency;
    //  Amount of synths borrowed
    uint amount;
    // Indicates if the position was short sold
    bool short;
    // interest amounts accrued
    uint accruedInterest;
    // last interest index
    uint interestIndex;
    // time of last interaction.
    uint lastInteraction;
  }

  function loans(uint id)
    external
    returns (
      uint,
      address,
      uint,
      bytes32,
      uint,
      bool,
      uint,
      uint,
      uint
    );

  function minCratio() external returns (uint);

  function minCollateral() external returns (uint);

  function issueFeeRate() external returns (uint);

  function open(
    uint collateral,
    uint amount,
    bytes32 currency
  ) external returns (uint id);

  function repay(
    address borrower,
    uint id,
    uint amount
  ) external returns (uint short, uint collateral);

  function repayWithCollateral(uint id, uint repayAmount) external returns (uint short, uint collateral);

  function draw(uint id, uint amount) external returns (uint short, uint collateral);

  // Same as before
  function deposit(
    address borrower,
    uint id,
    uint amount
  ) external returns (uint short, uint collateral);

  // Same as before
  function withdraw(uint id, uint amount) external returns (uint short, uint collateral);

  // function to return the loan details in one call, without needing to know about the collateralstate
  function getShortAndCollateral(address account, uint id) external view returns (uint short, uint collateral);
}

File 12 of 14 : IExchangeRates.sol
//SPDX-License-Identifier:MIT
pragma solidity ^0.7.6;

// https://docs.synthetix.io/contracts/source/interfaces/iexchangerates
interface IExchangeRates {
  function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid);
}

File 13 of 14 : IExchanger.sol
//SPDX-License-Identifier:MIT
pragma solidity ^0.7.6;

// https://docs.synthetix.io/contracts/source/interfaces/iexchanger
interface IExchanger {
  function feeRateForExchange(bytes32 sourceCurrencyKey, bytes32 destinationCurrencyKey)
    external
    view
    returns (uint exchangeFeeRate);
}

File 14 of 14 : ISynthetix.sol
//SPDX-License-Identifier: ISC
pragma solidity >=0.7.6;

interface ISynthetix {
  function exchange(
    bytes32 sourceCurrencyKey,
    uint sourceAmount,
    bytes32 destinationCurrencyKey
  ) external returns (uint amountReceived);

  function exchangeOnBehalf(
    address exchangeForAddress,
    bytes32 sourceCurrencyKey,
    uint sourceAmount,
    bytes32 destinationCurrencyKey
  ) external returns (uint amountReceived);
}

Settings
{
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseFreed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedCollateralBase","type":"uint256"}],"name":"BaseFreed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedCollateralBase","type":"uint256"}],"name":"BaseLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"quoteSpent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountPurchased","type":"uint256"}],"name":"BasePurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quoteReceived","type":"uint256"}],"name":"BaseSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalAmountToLiquidate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseFreed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"quoteReceived","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedCollateralBase","type":"uint256"}],"name":"CollateralLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CollateralQuoteTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DeltaQuoteTransferredToPoolHedger","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"uint256","name":"certificateId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"quoteFreed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedCollateralQuote","type":"uint256"}],"name":"QuoteFreed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"quoteLocked","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedCollateralQuote","type":"uint256"}],"name":"QuoteLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountQuoteReserved","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalQuoteAmountReserved","type":"uint256"}],"name":"QuoteReserved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalQuoteAmountReserved","type":"uint256"}],"name":"ReservedQuoteSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"maxExpiryTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pricePerToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalQuoteAmountReserved","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBurnableForRound","type":"uint256"}],"name":"RoundEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lastMaxExpiryTimestamp","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newMaxExpiryTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalTokenSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenValue","type":"uint256"}],"name":"RoundStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":true,"internalType":"uint256","name":"certificateId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalQuoteAmountReserved","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"certificateId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBurnableForRound","type":"uint256"}],"name":"WithdrawSignaled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"certificateId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBurnableForRound","type":"uint256"}],"name":"WithdrawUnSignaled","type":"event"},{"inputs":[{"internalType":"uint256","name":"amountQuoteFreed","type":"uint256"},{"internalType":"uint256","name":"amountQuoteReserved","type":"uint256"},{"internalType":"uint256","name":"amountBaseFreed","type":"uint256"}],"name":"boardLiquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"expiryToTokenValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountBase","type":"uint256"}],"name":"freeBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"freeQuoteCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"basePrice","type":"uint256"},{"internalType":"contract ICollateralShort","name":"short","type":"address"}],"name":"getLiquidity","outputs":[{"components":[{"internalType":"uint256","name":"freeCollatLiquidity","type":"uint256"},{"internalType":"uint256","name":"usedCollatLiquidity","type":"uint256"},{"internalType":"uint256","name":"freeDeltaLiquidity","type":"uint256"},{"internalType":"uint256","name":"usedDeltaLiquidity","type":"uint256"}],"internalType":"struct ILiquidityPool.Liquidity","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"basePrice","type":"uint256"},{"internalType":"uint256","name":"usedDeltaLiquidity","type":"uint256"}],"name":"getTotalPoolValueQuote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ILyraGlobals","name":"_globals","type":"address"},{"internalType":"contract IOptionMarket","name":"_optionMarket","type":"address"},{"internalType":"contract ILiquidityCertificate","name":"_liquidityCertificate","type":"address"},{"internalType":"contract IPoolHedger","name":"_poolHedger","type":"address"},{"internalType":"contract IShortCollateral","name":"_shortCollateral","type":"address"},{"internalType":"contract IERC20","name":"_quoteAsset","type":"address"},{"internalType":"contract IERC20","name":"_baseAsset","type":"address"},{"internalType":"string[]","name":"_errorMessages","type":"string[]"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint256","name":"spotPrice","type":"uint256"},{"internalType":"bytes32","name":"quoteKey","type":"bytes32"},{"internalType":"bytes32","name":"baseKey","type":"bytes32"},{"internalType":"contract ISynthetix","name":"synthetix","type":"address"},{"internalType":"contract ICollateralShort","name":"short","type":"address"},{"internalType":"uint256","name":"quoteBaseFeeRate","type":"uint256"},{"internalType":"uint256","name":"baseQuoteFeeRate","type":"uint256"}],"internalType":"struct ILyraGlobals.ExchangeGlobals","name":"exchangeGlobals","type":"tuple"},{"components":[{"internalType":"uint256","name":"freeCollatLiquidity","type":"uint256"},{"internalType":"uint256","name":"usedCollatLiquidity","type":"uint256"},{"internalType":"uint256","name":"freeDeltaLiquidity","type":"uint256"},{"internalType":"uint256","name":"usedDeltaLiquidity","type":"uint256"}],"internalType":"struct ILiquidityPool.Liquidity","name":"liquidity","type":"tuple"}],"name":"lockBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"freeCollatLiq","type":"uint256"}],"name":"lockQuote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockedCollateral","outputs":[{"internalType":"uint256","name":"quote","type":"uint256"},{"internalType":"uint256","name":"base","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queuedQuoteFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"freeCollatLiq","type":"uint256"}],"name":"sendPremium","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendReservedQuote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"certificateId","type":"uint256"}],"name":"signalWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lastMaxExpiryTimestamp","type":"uint256"},{"internalType":"uint256","name":"newMaxExpiryTimestamp","type":"uint256"}],"name":"startRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenPriceQuote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"spotPrice","type":"uint256"},{"internalType":"bytes32","name":"quoteKey","type":"bytes32"},{"internalType":"bytes32","name":"baseKey","type":"bytes32"},{"internalType":"contract ISynthetix","name":"synthetix","type":"address"},{"internalType":"contract ICollateralShort","name":"short","type":"address"},{"internalType":"uint256","name":"quoteBaseFeeRate","type":"uint256"},{"internalType":"uint256","name":"baseQuoteFeeRate","type":"uint256"}],"internalType":"struct ILyraGlobals.ExchangeGlobals","name":"exchangeGlobals","type":"tuple"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferQuoteToHedge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"certificateId","type":"uint256"}],"name":"unSignalWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"certificateId","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

60806040526000600860006101000a816200001962000062565b8160ff0219169083151502179062000030620000c7565b5050506001600f62000041620000c7565b50503480156200005b57600080620000586200012e565b50505b506200019e565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b6040811015620000c257600081830152602081019050620000a6565b505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b60005b604081101562000129576000818301526020810190506200010d565b505050565b632a2a7adb598160e01b8152600481016020815285602082015260005b868110156200016b5780860151816040840101526020810190506200014b565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b615c6e80620001ae6000396000f3fe608060405234801561001957600080610016614491565b50505b506004361061014b5760003560e01c8063a00dad22116100c1578063d1201e3111610085578063d1201e311461034c578063db32232f14610368578063dc62c58114610384578063f238ff5c146103a0578063f3fef3a3146103bc578063fc395668146103ec5761014b565b8063a00dad22146102bb578063b952cc4a146102d7578063c3964372146102f6578063c677c58a14610312578063c9061b58146103305761014b565b806347e7ef241161011357806347e7ef241461020f57806354d269af1461023f578063699ba87b1461025b578063749aa2d9146102775780637e8b3f891461028157806390a80ece1461028b5761014b565b8063159317d0146101595780631ebcfe801461017757806321af3525146101935780633f2f757d146101c35780633f6b5019146101f3575b600080610156614491565b50505b61016161041c565b60405161016e91906157b0565b60405180910390f35b610191600480360381019061018c91906151d7565b61065b565b005b6101ad60048036038101906101a89190615191565b6109fd565b6040516101ba91906157b0565b60405180910390f35b6101dd60048036038101906101d8919061523b565b610c36565b6040516101ea9190615795565b60405180910390f35b61020d6004803603810190610208919061531f565b610e4d565b005b61022960048036038101906102249190614efd565b610fa8565b60405161023691906157b0565b60405180910390f35b6102596004803603810190610254919061501f565b611326565b005b610275600480360381019061027091906151d7565b61169d565b005b61027f611964565b005b610289611eba565b005b6102a560048036038101906102a091906151d7565b6127d1565b6040516102b291906157b0565b60405180910390f35b6102d560048036038101906102d09190615280565b6127f0565b005b6102df612b18565b6040516102ed9291906157cb565b60405180910390f35b610310600480360381019061030b91906152da565b612b38565b005b61031a612cdc565b60405161032791906157b0565b60405180910390f35b61034a60048036038101906103459190614f42565b612ce9565b005b61036660048036038101906103619190614efd565b612eeb565b005b610382600480360381019061037d91906151d7565b613132565b005b61039e600480360381019061039991906151d7565b6131a8565b005b6103ba60048036038101906103b591906152da565b6132a5565b005b6103d660048036038101906103d19190614efd565b613397565b6040516103e391906157b0565b60405180910390f35b610406600480360381019061040191906152da565b613d20565b60405161041391906157b0565b60405180910390f35b60008060008061042a6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166305b7f2f6600160009061046f6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1660026040518363ffffffff1660e01b81526004016104ab92919061564a565b60e06040518083038186806104be614562565b1580156104d3576000806104d0614491565b50505b505a6104dd6145c5565b50505050501580156104fc573d6000803e3d60006104f9614491565b50505b505050506040513d601f19601f82011682018060405250810190610520919061515f565b90506000600e61052e6144ff565b141561054557670de0b6b3a7640000915050610658565b60006106358260000151600460009061055c6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cbb7429d856080015186600001516040518363ffffffff1660e01b81526004016105bb92919061570a565b60206040518083038186806105ce614562565b1580156105e3576000806105e0614491565b50505b505a6105ed6145c5565b505050505015801561060c573d6000803e3d6000610609614491565b50505b505050506040513d601f19601f820116820180604052508101906106309190615209565b613d20565b9050610653600e6106446144ff565b82613ff990919063ffffffff16565b925050505b90565b6000600260009061066a6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638024818a836040518263ffffffff1660e01b81526004016106bf91906157b0565b60606040518083038186806106d2614562565b1580156106e7576000806106e4614491565b50505b505a6106f16145c5565b5050505050158015610710573d6000803e3d600061070d614491565b50505b505050506040513d601f19601f82011682018060405250810190610734919061512d565b9050600060016000906107456144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632eb6534f6040518163ffffffff1660e01b815260040160206040518083038186806107a2614562565b1580156107b7576000806107b4614491565b50505b505a6107c16145c5565b50505050501580156107e0573d6000803e3d60006107dd614491565b50505b505050506040513d601f19601f820116820180604052508101906108049190615209565b90506108186000836040015114600161402f565b6108508183602001511415801561084957506000601060008481526020019081526020016000206108476144ff565b145b600261402f565b6000826020015114156108915761087d8260000151600c61086f6144ff565b61409d90919063ffffffff16565b600c81906108896146c5565b5050506108f1565b6108e16108c960106000856020015181526020019081526020016000206108b66144ff565b8460000151613ff990919063ffffffff16565b600c6108d36144ff565b61409d90919063ffffffff16565b600c81906108ed6146c5565b5050505b60026000906108fe6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638fbf3f4b5a61093f61472a565b85846040518463ffffffff1660e01b815260040161095f93929190615613565b60006040518083038160008780610974614562565b15801561098957600080610986614491565b50505b505a610993614787565b5050505050501580156109b3573d6000803e3d60006109b0614491565b50505b50505050827fa030de897a3fbcd98618ebb6d64981072317ade7083ad8702bbcd0b867a5063e600c6109e36144ff565b6040516109f091906157b0565b60405180910390a2505050565b6000610a696004600090610a0f6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a610a4b61472a565b73ffffffffffffffffffffffffffffffffffffffff1614601161402f565b610a866001600f610a786144ff565b61409d90919063ffffffff16565b600f8190610a926146c5565b5050506000600f610aa16144ff565b90506000610ab785600001518660800151610c36565b905060008160400151905084811015610ace578094505b610bdd6005600090610ade6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6004600090610b236144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff16886040518363ffffffff1660e01b8152600401610b5e929190615673565b60206040518083038160008780610b73614562565b158015610b8857600080610b85614491565b50505b505a610b92614787565b505050505050158015610bb2573d6000803e3d6000610baf614491565b50505b505050506040513d601f19601f82011682018060405250810190610bd69190614fed565b600061402f565b7f78139c2f5eabfad75a88b7c1fe1d1e3851b441e2c5a7f792f95d8e1c6b9c636085604051610c0c91906157b0565b60405180910390a18493505050610c2f600f610c266144ff565b8214601461402f565b5092915050565b610c3e614887565b610c46614887565b6004600090610c536144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cbb7429d84866040518363ffffffff1660e01b8152600401610caa92919061570a565b6020604051808303818680610cbd614562565b158015610cd257600080610ccf614491565b50505b505a610cdc6145c5565b5050505050158015610cfb573d6000803e3d6000610cf8614491565b50505b505050506040513d601f19601f82011682018060405250810190610d1f9190615209565b816060018181525050610d65610d4a856009600101610d3c6144ff565b61412e90919063ffffffff16565b6009600001610d576144ff565b61409d90919063ffffffff16565b8160200181815250506000610d7e858360600151613d20565b9050600060036002830281610d8f57fe5b0490506000610da7828461415b90919063ffffffff16565b90508184602001511115610dd65783602001519150610dcf828461415b90919063ffffffff16565b9050610e00565b8084606001511115610dff5783606001519050610dfc818461415b90919063ffffffff16565b91505b5b610e1784606001518261415b90919063ffffffff16565b846040018181525050610e3784602001518361415b90919063ffffffff16565b8460000181815250508394505050505092915050565b610eb76001600090610e5d6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a610e9961472a565b73ffffffffffffffffffffffffffffffffffffffff1614601261402f565b610ec0836141e7565b610edc82600b610ece6144ff565b61409d90919063ffffffff16565b600b8190610ee86146c5565b5050507f26fdd62e661c6437a27feaa8bcd05f1567dba4aa031bc1c15e5243d472969d9b82600b610f176144ff565b604051610f259291906157cb565b60405180910390a1610f4c816009600101610f3e6144ff565b61415b90919063ffffffff16565b60096001018190610f5b6146c5565b5050507f5b5eb4c315d078b7384bec63e32d19bebdac730f44483dc358bd9085aa20ffb9816009600101610f8d6144ff565b604051610f9b9291906157cb565b60405180910390a1505050565b6000610fc682600d610fb86144ff565b61409d90919063ffffffff16565b600d8190610fd26146c5565b50505060006002600090610fe46144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663156e29f68585600160009061102b6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632eb6534f6040518163ffffffff1660e01b81526004016020604051808303818680611088614562565b15801561109d5760008061109a614491565b50505b505a6110a76145c5565b50505050501580156110c6573d6000803e3d60006110c3614491565b50505b505050506040513d601f19601f820116820180604052508101906110ea9190615209565b6040518463ffffffff1660e01b81526004016111089392919061569c565b6020604051808303816000878061111d614562565b1580156111325760008061112f614491565b50505b505a61113c614787565b50505050505015801561115c573d6000803e3d6000611159614491565b50505b505050506040513d601f19601f820116820180604052508101906111809190615209565b9050808473ffffffffffffffffffffffffffffffffffffffff167f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15856040516111c991906157b0565b60405180910390a361131c60056000906111e16144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd5a61122261472a565b5a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b604081101561127b57600081830152602081019050611261565b505050876040518463ffffffff1660e01b815260040161129d9392919061557c565b602060405180830381600087806112b2614562565b1580156112c7576000806112c4614491565b50505b505a6112d1614787565b5050505050501580156112f1573d6000803e3d60006112ee614491565b50505b505050506040513d601f19601f820116820180604052508101906113159190614fed565b600061402f565b8091505092915050565b60086000906113336144ff565b906101000a900460ff1615611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137490615755565b60405180910390611383614491565b50505b876000806101000a816113976144ff565b8173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217906113d36146c5565b50505086600160006101000a816113e86144ff565b8173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217906114246146c5565b50505085600260006101000a816114396144ff565b8173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217906114756146c5565b50505083600360006101000a8161148a6144ff565b8173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217906114c66146c5565b50505084600460006101000a816114db6144ff565b8173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217906115176146c5565b50505082600560006101000a8161152c6144ff565b8173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217906115686146c5565b50505081600660006101000a8161157d6144ff565b8173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217906115b96146c5565b5050506015808111156115c857fe5b815114611613576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161160190615775565b60405180910390611610614491565b50505b60005b81518110156116675781818151811061162b57fe5b60200260200101516007600083815260200190815260200160002090805190602001906116599291906148af565b508080600101915050611616565b506001600860006101000a8161167b6144ff565b8160ff021916908315150217906116906146c5565b5050505050505050505050565b600060026000906116ac6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638024818a836040518263ffffffff1660e01b815260040161170191906157b0565b6060604051808303818680611714614562565b15801561172957600080611726614491565b50505b505a6117336145c5565b5050505050158015611752573d6000803e3d600061174f614491565b50505b505050506040513d601f19601f82011682018060405250810190611776919061512d565b905061178b600082604001511415600361402f565b6117b7600060106000846040015181526020019081526020016000206117af6144ff565b14600461402f565b60026000906117c46144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638fbf3f4b5a61180561472a565b8460006040518463ffffffff1660e01b8152600401611826939291906155dc565b6000604051808303816000878061183b614562565b1580156118505760008061184d614491565b50505b505a61185a614787565b50505050505015801561187a573d6000803e3d6000611877614491565b50505b505050506000816020015114156118bf576118ab8160000151600c61189d6144ff565b61415b90919063ffffffff16565b600c81906118b76146c5565b50505061191f565b61190f6118f760106000846020015181526020019081526020016000206118e46144ff565b8360000151613ff990919063ffffffff16565b600c6119016144ff565b61415b90919063ffffffff16565b600c819061191b6146c5565b5050505b817f74e46e4569fdcca3333564a0997a08b4607c2af89cd8477813db852c9f364b61600c61194b6144ff565b60405161195891906157b0565b60405180910390a25050565b600060016000906119736144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632eb6534f6040518163ffffffff1660e01b815260040160206040518083038186806119d0614562565b1580156119e5576000806119e2614491565b50505b505a6119ef6145c5565b5050505050158015611a0e573d6000803e3d6000611a0b614491565b50505b505050506040513d601f19601f82011682018060405250810190611a329190615209565b9050611b1360006001600090611a466144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637e7088eb6040518163ffffffff1660e01b81526004016000604051808303818680611aa3614562565b158015611ab857600080611ab5614491565b50505b505a611ac26145c5565b5050505050158015611ae1573d6000803e3d6000611ade614491565b50505b505050506040513d6000823e3d601f19601f82011682018060405250810190611b0a9190614f9a565b5114600661402f565b611b3b600060106000848152602001908152602001600020611b336144ff565b14600761402f565b611c7a60006006600090611b4d6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082315a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b6040811015611bde57600081830152602081019050611bc4565b5050506040518263ffffffff1660e01b8152600401611bfd9190615561565b6020604051808303818680611c10614562565b158015611c2557600080611c22614491565b50505b505a611c2f6145c5565b5050505050158015611c4e573d6000803e3d6000611c4b614491565b50505b505050506040513d601f19601f82011682018060405250810190611c729190615209565b14600861402f565b611d5360006004600090611c8c6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663759d4d596040518163ffffffff1660e01b81526004016020604051808303818680611ce9614562565b158015611cfe57600080611cfb614491565b50505b505a611d086145c5565b5050505050158015611d27573d6000803e3d6000611d24614491565b50505b505050506040513d601f19601f82011682018060405250810190611d4b91906150fb565b14600961402f565b6000611d5d61041c565b905080601060008481526020019081526020016000208190611d7d6146c5565b505050611db7611d9f82600c611d916144ff565b61412e90919063ffffffff16565b600b611da96144ff565b61409d90919063ffffffff16565b600b8190611dc36146c5565b5050507f26fdd62e661c6437a27feaa8bcd05f1567dba4aa031bc1c15e5243d472969d9b611e0382600c611df56144ff565b61412e90919063ffffffff16565b600b611e0d6144ff565b604051611e1b9291906157cb565b60405180910390a1611e48600c611e306144ff565b600e611e3a6144ff565b61415b90919063ffffffff16565b600e8190611e546146c5565b505050817fff9d41e1547acb5eda1e3bac0c795f57760c96016cdd641af6bdd90270a768f382600b611e846144ff565b600c611e8e6144ff565b604051611e9d939291906157f4565b60405180910390a26000600c8190611eb36146c5565b5050505050565b611ed76001600f611ec96144ff565b61409d90919063ffffffff16565b600f8190611ee36146c5565b5050506000600f611ef26144ff565b905060006006600090611f036144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082315a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b6040811015611f9457600081830152602081019050611f7a565b5050506040518263ffffffff1660e01b8152600401611fb39190615561565b6020604051808303818680611fc6614562565b158015611fdb57600080611fd8614491565b50505b505a611fe56145c5565b5050505050158015612004573d6000803e3d6000612001614491565b50505b505050506040513d601f19601f820116820180604052508101906120289190615209565b9050600060016000906120396144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637e7088eb6040518163ffffffff1660e01b81526004016000604051808303818680612096614562565b1580156120ab576000806120a8614491565b50505b505a6120b56145c5565b50505050501580156120d4573d6000803e3d60006120d1614491565b50505b505050506040513d6000823e3d601f19601f820116820180604052508101906120fd9190614f9a565b511415612119576000600960010181906121156146c5565b5050505b60096001016121266144ff565b8111156123795760008060009061213b6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166305b7f2f660016000906121806144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1660006040518363ffffffff1660e01b81526004016121bc92919061564a565b60e06040518083038186806121cf614562565b1580156121e4576000806121e1614491565b50505b505a6121ee6145c5565b505050505015801561220d573d6000803e3d600061220a614491565b50505b505050506040513d601f19601f82011682018060405250810190612231919061515f565b9050600060096001016122426144ff565b830390506000826060015173ffffffffffffffffffffffffffffffffffffffff1663ee52a2f384604001518486602001516040518463ffffffff1660e01b8152600401612291939291906156d3565b602060405180830381600087806122a6614562565b1580156122bb576000806122b8614491565b50505b505a6122c5614787565b5050505050501580156122e5573d6000803e3d60006122e2614491565b50505b505050506040513d601f19601f820116820180604052508101906123099190615209565b905061231960008211600b61402f565b5a61232261472a565b73ffffffffffffffffffffffffffffffffffffffff167f0ba93b4b06f63170434e95713b6e4613651536fe0795f417db31ca847d25e0f283836040516123699291906157cb565b60405180910390a25050506127b7565b8060096001016123876144ff565b11156127b65760008060009061239b6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166305b7f2f660016000906123e06144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1660016040518363ffffffff1660e01b815260040161241c92919061564a565b60e060405180830381868061242f614562565b15801561244457600080612441614491565b50505b505a61244e6145c5565b505050505015801561246d573d6000803e3d600061246a614491565b50505b505050506040513d601f19601f82011682018060405250810190612491919061515f565b905060006124e982600001516124db6124be8560a00151601260ff16600a0a61415b90919063ffffffff16565b8660096001016124cc6144ff565b0361428490919063ffffffff16565b6142a090919063ffffffff16565b90506000612673600d6124fa6144ff565b612665600960000161250a6144ff565b612657600b6125176144ff565b60056000906125246144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082315a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b60408110156125b55760008183015260208101905061259b565b5050506040518263ffffffff1660e01b81526004016125d49190615561565b60206040518083038186806125e7614562565b1580156125fc576000806125f9614491565b50505b505a6126066145c5565b5050505050158015612625573d6000803e3d6000612622614491565b50505b505050506040513d601f19601f820116820180604052508101906126499190615209565b61415b90919063ffffffff16565b61415b90919063ffffffff16565b61415b90919063ffffffff16565b90508082116126825781612684565b805b91506000836060015173ffffffffffffffffffffffffffffffffffffffff1663ee52a2f385602001518587604001516040518463ffffffff1660e01b81526004016126d1939291906156d3565b602060405180830381600087806126e6614562565b1580156126fb576000806126f8614491565b50505b505a612705614787565b505050505050158015612725573d6000803e3d6000612722614491565b50505b505050506040513d601f19601f820116820180604052508101906127499190615209565b905061275960008211600c61402f565b5a61276261472a565b73ffffffffffffffffffffffffffffffffffffffff167ffe644b4d06ffe999b33590d87654491fea7d9ce296e8d305004cf50ca96e6be184836040516127a99291906157cb565b60405180910390a2505050505b5b506127ce600f6127c56144ff565b8214601461402f565b50565b60106020528060005260406000206000915090506127ed6144ff565b81565b61285a60016000906128006144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a61283c61472a565b73ffffffffffffffffffffffffffffffffffffffff1614601261402f565b600060066000906128696144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082315a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b60408110156128fa576000818301526020810190506128e0565b5050506040518263ffffffff1660e01b81526004016129199190615561565b602060405180830381868061292c614562565b1580156129415760008061293e614491565b50505b505a61294b6145c5565b505050505015801561296a573d6000803e3d6000612967614491565b50505b505050506040513d601f19601f8201168201806040525081019061298e9190615209565b9050600080836000015190508260096001016129a86144ff565b10612a065760008360096001016129bd6144ff565b0390506129e96129da87600001518361412e90919063ffffffff16565b8361409d90919063ffffffff16565b91506129fe818861409d90919063ffffffff16565b925050612a41565b60006009600101612a156144ff565b84039050868110612a295760009250612a3f565b612a3c818861415b90919063ffffffff16565b92505b505b6000612a898660000151612a7b612a6c8960a00151601260ff16600a0a61415b90919063ffffffff16565b8661428490919063ffffffff16565b6142a090919063ffffffff16565b9050612a9981831015600e61402f565b612ab8876009600101612aaa6144ff565b61409d90919063ffffffff16565b60096001018190612ac76146c5565b5050507f88cdc2d9dafaa25ef0f861c37488527fa03d0d30cd7ed982e93c2fd8ed44eeaa876009600101612af96144ff565b604051612b079291906157cb565b60405180910390a150505050505050565b600980600001612b266144ff565b9080600101612b336144ff565b905082565b612ba26001600090612b486144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a612b8461472a565b73ffffffffffffffffffffffffffffffffffffffff1614601261402f565b6000821415612bc957600d612bb56144ff565b600e8190612bc16146c5565b505050612c53565b612bf2600060106000858152602001908152602001600020612be96144ff565b1415600a61402f565b612c43612c2b60106000858152602001908152602001600020612c136144ff565b600d612c1d6144ff565b613ff990919063ffffffff16565b600e612c356144ff565b61409d90919063ffffffff16565b600e8190612c4f6146c5565b5050505b6000600d8190612c616146c5565b50505080827ffd9d17e5565deea3d25918d95fc398673b9445ef0a96d12eaf3ab2b198756c65600e612c916144ff565b60008614612cb95760106000878152602001908152602001600020612cb46144ff565b612cc2565b601260ff16600a0a5b604051612cd09291906157cb565b60405180910390a35050565b600d612ce66144ff565b81565b612d536001600090612cf96144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a612d3561472a565b73ffffffffffffffffffffffffffffffffffffffff1614601261402f565b612d706001600f612d626144ff565b61409d90919063ffffffff16565b600f8190612d7c6146c5565b5050506000600f612d8b6144ff565b9050612d9b83831015601061402f565b612e816005600090612dab6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb86866040518363ffffffff1660e01b8152600401612e02929190615673565b60206040518083038160008780612e17614562565b158015612e2c57600080612e29614491565b50505b505a612e36614787565b505050505050158015612e56573d6000803e3d6000612e53614491565b50505b505050506040513d601f19601f82011682018060405250810190612e7a9190614fed565b600061402f565b8373ffffffffffffffffffffffffffffffffffffffff167f72debe083e16f39475584adf69a588657185fbd31e7627daa95ed7dbd45b3cc184604051612ec791906157b0565b60405180910390a2612ee5600f612edc6144ff565b8214601461402f565b50505050565b612f556003600090612efb6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a612f3761472a565b73ffffffffffffffffffffffffffffffffffffffff1614601361402f565b612f726001600f612f646144ff565b61409d90919063ffffffff16565b600f8190612f7e6146c5565b5050506000600f612f8d6144ff565b9050600b612f996144ff565b821115612fad57600b612faa6144ff565b91505b612fc982600b612fbb6144ff565b61415b90919063ffffffff16565b600b8190612fd56146c5565b5050506130be6005600090612fe86144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040518363ffffffff1660e01b815260040161303f929190615673565b60206040518083038160008780613054614562565b15801561306957600080613066614491565b50505b505a613073614787565b505050505050158015613093573d6000803e3d6000613090614491565b50505b505050506040513d601f19601f820116820180604052508101906130b79190614fed565b600061402f565b8273ffffffffffffffffffffffffffffffffffffffff167f10913cbb30d5b8ffef79cb59f0875923e51b1a5a54fb330d0cb2022e6af8d13483600b6131016144ff565b60405161310f9291906157cb565b60405180910390a261312d600f6131246144ff565b8214601461402f565b505050565b61319c60016000906131426144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a61317e61472a565b73ffffffffffffffffffffffffffffffffffffffff1614601261402f565b6131a5816141e7565b50565b61321260016000906131b86144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a6131f461472a565b73ffffffffffffffffffffffffffffffffffffffff1614601261402f565b61322c60096001016132226144ff565b821115600f61402f565b61324b81600960010161323d6144ff565b61415b90919063ffffffff16565b6009600101819061325a6146c5565b5050507f5b5eb4c315d078b7384bec63e32d19bebdac730f44483dc358bd9085aa20ffb981600960010161328c6144ff565b60405161329a9291906157cb565b60405180910390a150565b61330f60016000906132b56144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff165a6132f161472a565b73ffffffffffffffffffffffffffffffffffffffff1614601261402f565b61331d81831115600d61402f565b61333c82600960000161332e6144ff565b61409d90919063ffffffff16565b6009600001819061334b6146c5565b5050507fa926f60433937c9b276382ddb5204387c2c70104cbe627db98999c7d706c419682600960000161337d6144ff565b60405161338b9291906157cb565b60405180910390a15050565b60008060026000906133a76144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638024818a846040518263ffffffff1660e01b81526004016133fc91906157b0565b606060405180830381868061340f614562565b15801561342457600080613421614491565b50505b505a61342e6145c5565b505050505015801561344d573d6000803e3d600061344a614491565b50505b505050506040513d601f19601f82011682018060405250810190613471919061512d565b9050600060016000906134826144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632eb6534f6040518163ffffffff1660e01b815260040160206040518083038186806134df614562565b1580156134f4576000806134f1614491565b50505b505a6134fe6145c5565b505050505015801561351d573d6000803e3d600061351a614491565b50505b505050506040513d601f19601f820116820180604052508101906135419190615209565b905080826020015114156137985761356f8260000151600d6135616144ff565b61415b90919063ffffffff16565b600d819061357b6146c5565b505050600260009061358b6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac5a6135cc61472a565b866040518363ffffffff1660e01b81526004016135ea9291906155b3565b600060405180830381600087806135ff614562565b15801561361457600080613611614491565b50505b505a61361e614787565b50505050505015801561363e573d6000803e3d600061363b614491565b50505b50505050838573ffffffffffffffffffffffffffffffffffffffff167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca948460000151600b61368a6144ff565b6040516136989291906157cb565b60405180910390a361378a60056000906136b06144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8785600001516040518363ffffffff1660e01b815260040161370b929190615673565b60206040518083038160008780613720614562565b15801561373557600080613732614491565b50505b505a61373f614787565b50505050505015801561375f573d6000803e3d600061375c614491565b50505b505050506040513d601f19601f820116820180604052508101906137839190614fed565b600061402f565b816000015192505050613d1a565b6000808360200151146137c95760106000846020015181526020019081526020016000206137c46144ff565b6137d3565b670de0b6b3a76400005b90506000601060008481526020019081526020016000206137f26144ff565b905060008460400151148015613809575060008114155b15613a77576000613827838660000151613ff990919063ffffffff16565b905061384581600e6138376144ff565b61415b90919063ffffffff16565b600e81906138516146c5565b505050613867828261412e90919063ffffffff16565b955060026000906138766144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac5a6138b761472a565b896040518363ffffffff1660e01b81526004016138d59291906155b3565b600060405180830381600087806138ea614562565b1580156138ff576000806138fc614491565b50505b505a613909614787565b505050505050158015613929573d6000803e3d6000613926614491565b50505b50505050868873ffffffffffffffffffffffffffffffffffffffff167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9488600b6139716144ff565b60405161397f9291906157cb565b60405180910390a3613a6d60056000906139976144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a896040518363ffffffff1660e01b81526004016139ee929190615673565b60206040518083038160008780613a03614562565b158015613a1857600080613a15614491565b50505b505a613a22614787565b505050505050158015613a42573d6000803e3d6000613a3f614491565b50505b505050506040513d601f19601f82011682018060405250810190613a669190614fed565b600061402f565b5050505050613d1a565b60006010600086604001518152602001908152602001600020613a986144ff565b9050613aba6000866040015114158015613ab3575060008214155b600561402f565b613ae383613ad583886000015161412e90919063ffffffff16565b613ff990919063ffffffff16565b95506002600090613af26144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac5a613b3361472a565b896040518363ffffffff1660e01b8152600401613b519291906155b3565b60006040518083038160008780613b66614562565b158015613b7b57600080613b78614491565b50505b505a613b85614787565b505050505050158015613ba5573d6000803e3d6000613ba2614491565b50505b50505050613bc586600b613bb76144ff565b61415b90919063ffffffff16565b600b8190613bd16146c5565b505050868873ffffffffffffffffffffffffffffffffffffffff167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9488600b613c186144ff565b604051613c269291906157cb565b60405180910390a3613d146005600090613c3e6144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a896040518363ffffffff1660e01b8152600401613c95929190615673565b60206040518083038160008780613caa614562565b158015613cbf57600080613cbc614491565b50505b505a613cc9614787565b505050505050158015613ce9573d6000803e3d6000613ce6614491565b50505b505050506040513d601f19601f82011682018060405250810190613d0d9190614fed565b600061402f565b50505050505b92915050565b6000613ff1600d613d2f6144ff565b613fe3600b613d3c6144ff565b613fd586613fc7613e878a6006600090613d546144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082315a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b6040811015613de557600081830152602081019050613dcb565b5050506040518263ffffffff1660e01b8152600401613e049190615561565b6020604051808303818680613e17614562565b158015613e2c57600080613e29614491565b50505b505a613e366145c5565b5050505050158015613e55573d6000803e3d6000613e52614491565b50505b505050506040513d601f19601f82011682018060405250810190613e799190615209565b61412e90919063ffffffff16565b6005600090613e946144ff565b906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a082315a63996d79a5598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051925060005b6040811015613f2557600081830152602081019050613f0b565b5050506040518263ffffffff1660e01b8152600401613f449190615561565b6020604051808303818680613f57614562565b158015613f6c57600080613f69614491565b50505b505a613f766145c5565b5050505050158015613f95573d6000803e3d6000613f92614491565b50505b505050506040513d601f19601f82011682018060405250810190613fb99190615209565b61409d90919063ffffffff16565b61409d90919063ffffffff16565b61415b90919063ffffffff16565b61415b90919063ffffffff16565b905092915050565b600061402782614019601260ff16600a0a866142bc90919063ffffffff16565b61434b90919063ffffffff16565b905092915050565b816007600083601581111561404057fe5b815260200190815260200160002090614098576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016140869190615733565b60405180910390614095614491565b50505b505050565b600080828401905083811015614124576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390614121614491565b50505b8091505092915050565b6000601260ff16600a0a61414b83856142bc90919063ffffffff16565b8161415257fe5b04905092915050565b6000828211156141dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250602001915050604051809103906141d9614491565b50505b818303905092915050565b60096000016141f46144ff565b81111561420b5760096000016142086144ff565b90505b61422a81600960000161421c6144ff565b61415b90919063ffffffff16565b600960000181906142396146c5565b5050507f21035560539b4b4540708d4273620b634b00bda210e30692ec878ef00741cbc181600960000161426b6144ff565b6040516142799291906157cb565b60405180910390a150565b60006142988383601260ff16600a0a6143dd565b905092915050565b60006142b48383601260ff16600a0a614438565b905092915050565b6000808314156142cf5760009050614345565b60008284029050828482816142e057fe5b0414614340576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615c4d602191396040019150506040518091039061433d614491565b50505b809150505b92915050565b60008082116143cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250602001915050604051809103906143c8614491565b50505b8183816143d457fe5b04905092915050565b600080614408846143fa600a8602886142bc90919063ffffffff16565b61434b90919063ffffffff16565b90506005600a828161441657fe5b061061442357600a810190505b600a818161442d57fe5b049150509392505050565b600080600a838161444557fe5b0461445985876142bc90919063ffffffff16565b8161446057fe5b0490506005600a828161446f57fe5b061061447c57600a810190505b600a818161448657fe5b049150509392505050565b632a2a7adb598160e01b8152600481016020815285602082015260005b868110156144cc5780860151816040840101526020810190506144ae565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b604081101561455d57600081830152602081019050614543565b505050565b638435035b598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b60408110156145c0576000818301526020810190506145a6565b505050565b638540661f598160e01b8152614604565b6000819050818311156145e7578290505b92915050565b6000819050818310156145fe578290505b92915050565b836004820152846024820152606060448201528660648201526084810160005b8881101561463f578088015181830152602081019050614624565b506060828960a40184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b815160408301513d6000853e8b8b82606087013350600060045af150596146948d3d6145ed565b8c016146a081876145d6565b5b828110156146b857600081526020810190506146a1565b50839d5050505050505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b60005b60408110156147255760008183015260208101905061470b565b505050565b6373509064598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b604081101561478257600081830152602081019050614768565b505050565b6385979f76598160e01b81526147c6565b6000819050818311156147a9578290505b92915050565b6000819050818310156147c0578290505b92915050565b836004820152846024820152606060448201528760648201526084810160005b898110156148015780890151818301526020810190506147e6565b506060828a60a40184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b815160408301513d6000853e8c8c82606087013350600060045af150596148568e3d6147af565b8d016148628187614798565b5b8281101561487a5760008152602081019050614863565b50839e5050505050505050565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b82806148b96144ff565b600181600116156101000203166002900490600052602060002090601f0160209004810192826148f5576000856148ee6146c5565b5050614957565b82601f1061491757805160ff191683800117856149106146c5565b5050614957565b828001600101856149266146c5565b50508215614957579182015b82811115614956578251826149456146c5565b505091602001919060010190614932565b5b5090506149649190614968565b5090565b5b8082111561498a5760008160009061497f6146c5565b505050600101614969565b5090565b60006149a161499c8461585c565b61582b565b9050808382526020820190508260005b858110156149e157813585016149c78882614c48565b8452602084019350602083019250506001810190506149b1565b5050509392505050565b60006149fe6149f984615888565b61582b565b90508083825260208201905082856020860282011115614a2657600080614a23614491565b50505b60005b85811015614a565781614a3c8882614ee8565b845260208401935060208301925050600181019050614a29565b5050509392505050565b6000614a73614a6e846158b4565b61582b565b905082815260208101848484011115614a9457600080614a91614491565b50505b614a9f848285615a87565b509392505050565b600081359050614ab681615aac565b92915050565b600082601f830112614ad657600080614ad3614491565b50505b8135614ae684826020860161498e565b91505092915050565b600082601f830112614b0957600080614b06614491565b50505b8151614b198482602086016149eb565b91505092915050565b600081519050614b3181615acc565b92915050565b600081359050614b4681615aec565b92915050565b600081519050614b5b81615aec565b92915050565b600081359050614b7081615b0c565b92915050565b600081519050614b8581615b0c565b92915050565b600081359050614b9a81615b2c565b92915050565b600081359050614baf81615b4c565b92915050565b600081359050614bc481615b6c565b92915050565b600081359050614bd981615b8c565b92915050565b600081359050614bee81615bac565b92915050565b600081359050614c0381615bcc565b92915050565b600081359050614c1881615bec565b92915050565b600081519050614c2d81615bec565b92915050565b600081519050614c4281615c0c565b92915050565b600082601f830112614c6257600080614c5f614491565b50505b8135614c72848260208601614a60565b91505092915050565b600060608284031215614c9657600080614c93614491565b50505b614ca0606061582b565b90506000614cb084828501614ee8565b6000830152506020614cc484828501614ee8565b6020830152506040614cd884828501614ee8565b60408301525092915050565b600060e08284031215614cff57600080614cfc614491565b50505b614d0960e061582b565b90506000614d1984828501614ed3565b6000830152506020614d2d84828501614b37565b6020830152506040614d4184828501614b37565b6040830152506060614d5584828501614c09565b6060830152506080614d6984828501614b61565b60808301525060a0614d7d84828501614ed3565b60a08301525060c0614d9184828501614ed3565b60c08301525092915050565b600060e08284031215614db857600080614db5614491565b50505b614dc260e061582b565b90506000614dd284828501614ee8565b6000830152506020614de684828501614b4c565b6020830152506040614dfa84828501614b4c565b6040830152506060614e0e84828501614c1e565b6060830152506080614e2284828501614b76565b60808301525060a0614e3684828501614ee8565b60a08301525060c0614e4a84828501614ee8565b60c08301525092915050565b600060808284031215614e7157600080614e6e614491565b50505b614e7b608061582b565b90506000614e8b84828501614ed3565b6000830152506020614e9f84828501614ed3565b6020830152506040614eb384828501614ed3565b6040830152506060614ec784828501614ed3565b60608301525092915050565b600081359050614ee281615c2c565b92915050565b600081519050614ef781615c2c565b92915050565b60008060408385031215614f1957600080614f16614491565b50505b6000614f2785828601614aa7565b9250506020614f3885828601614ed3565b9150509250929050565b600080600060608486031215614f6057600080614f5d614491565b50505b6000614f6e86828701614aa7565b9350506020614f7f86828701614ed3565b9250506040614f9086828701614ed3565b9150509250925092565b600060208284031215614fb557600080614fb2614491565b50505b600082015167ffffffffffffffff811115614fd857600080614fd5614491565b50505b614fe484828501614aef565b91505092915050565b60006020828403121561500857600080615005614491565b50505b600061501684828501614b22565b91505092915050565b600080600080600080600080610100898b03121561504557600080615042614491565b50505b60006150538b828c01614bb5565b98505060206150648b828c01614bca565b97505060406150758b828c01614ba0565b96505060606150868b828c01614bdf565b95505060806150978b828c01614bf4565b94505060a06150a88b828c01614b8b565b93505060c06150b98b828c01614b8b565b92505060e089013567ffffffffffffffff8111156150df576000806150dc614491565b50505b6150eb8b828c01614abc565b9150509295985092959890939650565b60006020828403121561511657600080615113614491565b50505b600061512484828501614c33565b91505092915050565b60006060828403121561514857600080615145614491565b50505b600061515684828501614c7b565b91505092915050565b600060e0828403121561517a57600080615177614491565b50505b600061518884828501614d9d565b91505092915050565b60008061010083850312156151ae576000806151ab614491565b50505b60006151bc85828601614ce4565b92505060e06151cd85828601614ed3565b9150509250929050565b6000602082840312156151f2576000806151ef614491565b50505b600061520084828501614ed3565b91505092915050565b60006020828403121561522457600080615221614491565b50505b600061523284828501614ee8565b91505092915050565b6000806040838503121561525757600080615254614491565b50505b600061526585828601614ed3565b925050602061527685828601614b61565b9150509250929050565b6000806000610180848603121561529f5760008061529c614491565b50505b60006152ad86828701614ed3565b93505060206152be86828701614ce4565b9250506101006152d086828701614e56565b9150509250925092565b600080604083850312156152f6576000806152f3614491565b50505b600061530485828601614ed3565b925050602061531585828601614ed3565b9150509250929050565b60008060006060848603121561533d5760008061533a614491565b50505b600061534b86828701614ed3565b935050602061535c86828701614ed3565b925050604061536d86828701614ed3565b9150509250925092565b61538081615a09565b82525050565b61538f8161590a565b82525050565b61539e81615928565b82525050565b6153ad81615a1b565b82525050565b6153bc81615a3f565b82525050565b6153cb81615a51565b82525050565b6000816153dc6144ff565b60018116600081146153f5576001811461541b57615466565b607f600283041661540681876158f9565b955060ff198316865260208601935050615466565b6002820461542981876158f9565b9550615434856158e4565b60005b8281101561545d57816154486144ff565b81890152600182019150602081019050615437565b80880195505050505b505092915050565b600061547b6013836158f9565b91507f616c726561647920696e697469616c697a6564000000000000000000000000006000830152602082019050919050565b60006154bb600f836158f9565b91507f6572726f72206d736720636f756e7400000000000000000000000000000000006000830152602082019050919050565b6080820160008201516155046000850182615543565b5060208201516155176020850182615543565b50604082015161552a6040850182615543565b50606082015161553d6060850182615543565b50505050565b61554c816159ff565b82525050565b61555b816159ff565b82525050565b60006020820190506155766000830184615386565b92915050565b60006060820190506155916000830186615377565b61559e6020830185615386565b6155ab6040830184615552565b949350505050565b60006040820190506155c86000830185615377565b6155d56020830184615552565b9392505050565b60006060820190506155f16000830186615377565b6155fe6020830185615552565b61560b60408301846153c2565b949350505050565b60006060820190506156286000830186615377565b6156356020830185615552565b6156426040830184615552565b949350505050565b600060408201905061565f6000830185615386565b61566c60208301846153b3565b9392505050565b60006040820190506156886000830185615386565b6156956020830184615552565b9392505050565b60006060820190506156b16000830186615386565b6156be6020830185615552565b6156cb6040830184615552565b949350505050565b60006060820190506156e86000830186615395565b6156f56020830185615552565b6157026040830184615395565b949350505050565b600060408201905061571f60008301856153a4565b61572c6020830184615552565b9392505050565b6000602082019050818103600083015261574d81846153d1565b905092915050565b6000602082019050818103600083015261576e8161546e565b9050919050565b6000602082019050818103600083015261578e816154ae565b9050919050565b60006080820190506157aa60008301846154ee565b92915050565b60006020820190506157c56000830184615552565b92915050565b60006040820190506157e06000830185615552565b6157ed6020830184615552565b9392505050565b60006060820190506158096000830186615552565b6158166020830185615552565b6158236040830184615552565b949350505050565b6000604051905081810181811067ffffffffffffffff8211171561585257615851615a96565b5b8060405250919050565b600067ffffffffffffffff82111561587757615876615a96565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156158a3576158a2615a96565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156158cf576158ce615a96565b5b601f19601f8301169050602081019050919050565b60008190508160005260206000209050919050565b600082825260208201905092915050565b6000615915826159df565b9050919050565b60008115159050919050565b6000819050919050565b600061593d8261590a565b9050919050565b600061594f8261590a565b9050919050565b60006159618261590a565b9050919050565b60006159738261590a565b9050919050565b60006159858261590a565b9050919050565b60006159978261590a565b9050919050565b60006159a98261590a565b9050919050565b60006159bb8261590a565b9050919050565b60008190506159d082615a98565b919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000615a1482615a63565b9050919050565b6000615a2682615a2d565b9050919050565b6000615a38826159df565b9050919050565b6000615a4a826159c2565b9050919050565b6000615a5c826159ff565b9050919050565b6000615a6e82615a75565b9050919050565b6000615a80826159df565b9050919050565b82818337600083830152505050565bfe5b60038110615aa957615aa8615a96565b5b50565b615ab58161590a565b8114615ac957600080615ac6614491565b50505b50565b615ad58161591c565b8114615ae957600080615ae6614491565b50505b50565b615af581615928565b8114615b0957600080615b06614491565b50505b50565b615b1581615932565b8114615b2957600080615b26614491565b50505b50565b615b3581615944565b8114615b4957600080615b46614491565b50505b50565b615b5581615956565b8114615b6957600080615b66614491565b50505b50565b615b7581615968565b8114615b8957600080615b86614491565b50505b50565b615b958161597a565b8114615ba957600080615ba6614491565b50505b50565b615bb58161598c565b8114615bc957600080615bc6614491565b50505b50565b615bd58161599e565b8114615be957600080615be6614491565b50505b50565b615bf5816159b0565b8114615c0957600080615c06614491565b50505b50565b615c15816159d5565b8114615c2957600080615c26614491565b50505b50565b615c35816159ff565b8114615c4957600080615c46614491565b50505b5056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101425760003560e01c8063a00dad22116100b8578063d1201e311161007c578063d1201e311461033a578063db32232f14610356578063dc62c58114610372578063f238ff5c1461038e578063f3fef3a3146103aa578063fc395668146103da57610142565b8063a00dad22146102a9578063b952cc4a146102c5578063c3964372146102e4578063c677c58a14610300578063c9061b581461031e57610142565b806347e7ef241161010a57806347e7ef24146101fd57806354d269af1461022d578063699ba87b14610249578063749aa2d9146102655780637e8b3f891461026f57806390a80ece1461027957610142565b8063159317d0146101475780631ebcfe801461016557806321af3525146101815780633f2f757d146101b15780633f6b5019146101e1575b600080fd5b61014f61040a565b60405161015c91906144d1565b60405180910390f35b61017f600480360381019061017a9190613f3c565b6105dc565b005b61019b60048036038101906101969190613eff565b6108bc565b6040516101a891906144d1565b60405180910390f35b6101cb60048036038101906101c69190613f8e565b610a94565b6040516101d891906144b6565b60405180910390f35b6101fb60048036038101906101f69190614057565b610c71565b005b61021760048036038101906102129190613cc5565b610d8f565b60405161022491906144d1565b60405180910390f35b61024760048036038101906102429190613dba565b611014565b005b610263600480360381019061025e9190613f3c565b6112f2565b005b61026d611523565b005b61027761190b565b005b610293600480360381019061028e9190613f3c565b611fce565b6040516102a091906144d1565b60405180910390f35b6102c360048036038101906102be9190613fca565b611fe6565b005b6102cd61224c565b6040516102db9291906144ec565b60405180910390f35b6102fe60048036038101906102f9919061401b565b61225e565b005b6103086123a7565b60405161031591906144d1565b60405180910390f35b61033860048036038101906103339190613d01565b6123ad565b005b610354600480360381019061034f9190613cc5565b612555565b005b610370600480360381019061036b9190613f3c565b61271d565b005b61038c60048036038101906103879190613f3c565b612784565b005b6103a860048036038101906103a3919061401b565b612854565b005b6103c460048036038101906103bf9190613cc5565b612920565b6040516103d191906144d1565b60405180910390f35b6103f460048036038101906103ef919061401b565b6130d1565b60405161040191906144d1565b60405180910390f35b60008060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166305b7f2f6600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660026040518363ffffffff1660e01b815260040161048b92919061436b565b60e06040518083038186803b1580156104a357600080fd5b505afa1580156104b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104db9190613ed6565b90506000600e5414156104f957670de0b6b3a76400009150506105d9565b60006105bd8260000151600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cbb7429d856080015186600001516040518363ffffffff1660e01b815260040161056892919061442b565b60206040518083038186803b15801561058057600080fd5b505afa158015610594573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b89190613f65565b6130d1565b90506105d4600e548261328e90919063ffffffff16565b925050505b90565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638024818a836040518263ffffffff1660e01b815260040161063991906144d1565b60606040518083038186803b15801561065157600080fd5b505afa158015610665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106899190613ead565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632eb6534f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156106f557600080fd5b505afa158015610709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072d9190613f65565b9050610741600083604001511460016132c4565b6107728183602001511415801561076b575060006010600084815260200190815260200160002054145b60026132c4565b6000826020015114156107a3576107988260000151600c5461332990919063ffffffff16565b600c819055506107ec565b6107e56107d4601060008560200151815260200190815260200160002054846000015161328e90919063ffffffff16565b600c5461332990919063ffffffff16565b600c819055505b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638fbf3f4b3385846040518463ffffffff1660e01b815260040161084b93929190614334565b600060405180830381600087803b15801561086557600080fd5b505af1158015610879573d6000803e3d6000fd5b50505050827fa030de897a3fbcd98618ebb6d64981072317ade7083ad8702bbcd0b867a5063e600c546040516108af91906144d1565b60405180910390a2505050565b6000610919600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460116132c4565b61092f6001600f5461332990919063ffffffff16565b600f819055506000600f549050600061095085600001518660800151610a94565b905060008160400151905084811015610967578094505b610a42600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16886040518363ffffffff1660e01b81526004016109e9929190614394565b602060405180830381600087803b158015610a0357600080fd5b505af1158015610a17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3b9190613d91565b60006132c4565b7f78139c2f5eabfad75a88b7c1fe1d1e3851b441e2c5a7f792f95d8e1c6b9c636085604051610a7191906144d1565b60405180910390a18493505050610a8d600f54821460146132c4565b5092915050565b610a9c6136d4565b610aa46136d4565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cbb7429d84866040518363ffffffff1660e01b8152600401610b0192919061442b565b60206040518083038186803b158015610b1957600080fd5b505afa158015610b2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b519190613f65565b816060018181525050610b89610b75856009600101546133b190919063ffffffff16565b60096000015461332990919063ffffffff16565b8160200181815250506000610ba28583606001516130d1565b9050600060036002830281610bb357fe5b0490506000610bcb82846133de90919063ffffffff16565b90508184602001511115610bfa5783602001519150610bf382846133de90919063ffffffff16565b9050610c24565b8084606001511115610c235783606001519050610c2081846133de90919063ffffffff16565b91505b5b610c3b8460600151826133de90919063ffffffff16565b846040018181525050610c5b8460200151836133de90919063ffffffff16565b8460000181815250508394505050505092915050565b610ccc600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460126132c4565b610cd583613461565b610cea82600b5461332990919063ffffffff16565b600b819055507f26fdd62e661c6437a27feaa8bcd05f1567dba4aa031bc1c15e5243d472969d9b82600b54604051610d239291906144ec565b60405180910390a1610d43816009600101546133de90919063ffffffff16565b6009600101819055507f5b5eb4c315d078b7384bec63e32d19bebdac730f44483dc358bd9085aa20ffb981600960010154604051610d829291906144ec565b60405180910390a1505050565b6000610da682600d5461332990919063ffffffff16565b600d819055506000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663156e29f68585600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632eb6534f6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5657600080fd5b505afa158015610e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8e9190613f65565b6040518463ffffffff1660e01b8152600401610eac939291906143bd565b602060405180830381600087803b158015610ec657600080fd5b505af1158015610eda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610efe9190613f65565b9050808473ffffffffffffffffffffffffffffffffffffffff167f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1585604051610f4791906144d1565b60405180910390a361100a600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330876040518463ffffffff1660e01b8152600401610fb19392919061429d565b602060405180830381600087803b158015610fcb57600080fd5b505af1158015610fdf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110039190613d91565b60006132c4565b8091505092915050565b600860009054906101000a900460ff1615611064576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161105b90614476565b60405180910390fd5b876000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555086600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555084600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060158081111561123657fe5b815114611278576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161126f90614496565b60405180910390fd5b60005b81518110156112cc5781818151811061129057fe5b60200260200101516007600083815260200190815260200160002090805190602001906112be9291906136fc565b50808060010191505061127b565b506001600860006101000a81548160ff0219169083151502179055505050505050505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638024818a836040518263ffffffff1660e01b815260040161134f91906144d1565b60606040518083038186803b15801561136757600080fd5b505afa15801561137b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139f9190613ead565b90506113b460008260400151141560036132c4565b6113d960006010600084604001518152602001908152602001600020541460046132c4565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638fbf3f4b338460006040518463ffffffff1660e01b8152600401611439939291906142fd565b600060405180830381600087803b15801561145357600080fd5b505af1158015611467573d6000803e3d6000fd5b5050505060008160200151141561149c576114918160000151600c546133de90919063ffffffff16565b600c819055506114e5565b6114de6114cd601060008460200151815260200190815260200160002054836000015161328e90919063ffffffff16565b600c546133de90919063ffffffff16565b600c819055505b817f74e46e4569fdcca3333564a0997a08b4607c2af89cd8477813db852c9f364b61600c5460405161151791906144d1565b60405180910390a25050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632eb6534f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561158d57600080fd5b505afa1580156115a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c59190613f65565b905061167a6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637e7088eb6040518163ffffffff1660e01b815260040160006040518083038186803b15801561163457600080fd5b505afa158015611648573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906116719190613d50565b511460066132c4565b61169b600060106000848152602001908152602001600020541460076132c4565b6117536000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016116fb9190614282565b60206040518083038186803b15801561171357600080fd5b505afa158015611727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174b9190613f65565b1460086132c4565b6118006000600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663759d4d596040518163ffffffff1660e01b815260040160206040518083038186803b1580156117c057600080fd5b505afa1580156117d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f89190613e84565b1460096132c4565b600061180a61040a565b905080601060008481526020019081526020016000208190555061184d61183c82600c546133b190919063ffffffff16565b600b5461332990919063ffffffff16565b600b819055507f26fdd62e661c6437a27feaa8bcd05f1567dba4aa031bc1c15e5243d472969d9b61188982600c546133b190919063ffffffff16565b600b5460405161189a9291906144ec565b60405180910390a16118b9600c54600e546133de90919063ffffffff16565b600e81905550817fff9d41e1547acb5eda1e3bac0c795f57760c96016cdd641af6bdd90270a768f382600b54600c546040516118f793929190614515565b60405180910390a26000600c819055505050565b6119216001600f5461332990919063ffffffff16565b600f819055506000600f5490506000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161198b9190614282565b60206040518083038186803b1580156119a357600080fd5b505afa1580156119b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119db9190613f65565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637e7088eb6040518163ffffffff1660e01b815260040160006040518083038186803b158015611a4757600080fd5b505afa158015611a5b573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190611a849190613d50565b511415611a975760006009600101819055505b600960010154811115611c885760008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166305b7f2f6600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660006040518363ffffffff1660e01b8152600401611b2592919061436b565b60e06040518083038186803b158015611b3d57600080fd5b505afa158015611b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b759190613ed6565b90506000600960010154830390506000826060015173ffffffffffffffffffffffffffffffffffffffff1663ee52a2f384604001518486602001516040518463ffffffff1660e01b8152600401611bce939291906143f4565b602060405180830381600087803b158015611be857600080fd5b505af1158015611bfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c209190613f65565b9050611c3060008211600b6132c4565b3373ffffffffffffffffffffffffffffffffffffffff167f0ba93b4b06f63170434e95713b6e4613651536fe0795f417db31ca847d25e0f28383604051611c789291906144ec565b60405180910390a2505050611fbb565b806009600101541115611fba5760008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166305b7f2f6600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660016040518363ffffffff1660e01b8152600401611d1692919061436b565b60e06040518083038186803b158015611d2e57600080fd5b505afa158015611d42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d669190613ed6565b90506000611db78260000151611da9611d938560a00151601260ff16600a0a6133de90919063ffffffff16565b86600960010154036134d990919063ffffffff16565b6134f590919063ffffffff16565b90506000611ea5600d54611e97600960000154611e89600b54600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611e2b9190614282565b60206040518083038186803b158015611e4357600080fd5b505afa158015611e57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7b9190613f65565b6133de90919063ffffffff16565b6133de90919063ffffffff16565b6133de90919063ffffffff16565b9050808211611eb45781611eb6565b805b91506000836060015173ffffffffffffffffffffffffffffffffffffffff1663ee52a2f385602001518587604001516040518463ffffffff1660e01b8152600401611f03939291906143f4565b602060405180830381600087803b158015611f1d57600080fd5b505af1158015611f31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f559190613f65565b9050611f6560008211600c6132c4565b3373ffffffffffffffffffffffffffffffffffffffff167ffe644b4d06ffe999b33590d87654491fea7d9ce296e8d305004cf50ca96e6be18483604051611fad9291906144ec565b60405180910390a2505050505b5b50611fcb600f54821460146132c4565b50565b60106020528060005260406000206000915090505481565b612041600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460126132c4565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161209e9190614282565b60206040518083038186803b1580156120b657600080fd5b505afa1580156120ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ee9190613f65565b90506000808360000151905082600960010154106121585760008360096001015403905061213b61212c8760000151836133b190919063ffffffff16565b8361332990919063ffffffff16565b9150612150818861332990919063ffffffff16565b92505061218c565b600060096001015484039050868110612174576000925061218a565b61218781886133de90919063ffffffff16565b92505b505b60006121d486600001516121c66121b78960a00151601260ff16600a0a6133de90919063ffffffff16565b866134d990919063ffffffff16565b6134f590919063ffffffff16565b90506121e481831015600e6132c4565b6121fc8760096001015461332990919063ffffffff16565b6009600101819055507f88cdc2d9dafaa25ef0f861c37488527fa03d0d30cd7ed982e93c2fd8ed44eeaa8760096001015460405161223b9291906144ec565b60405180910390a150505050505050565b60098060000154908060010154905082565b6122b9600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460126132c4565b60008214156122d057600d54600e81905550612335565b6122f2600060106000858152602001908152602001600020541415600a6132c4565b61232e61231d6010600085815260200190815260200160002054600d5461328e90919063ffffffff16565b600e5461332990919063ffffffff16565b600e819055505b6000600d8190555080827ffd9d17e5565deea3d25918d95fc398673b9445ef0a96d12eaf3ab2b198756c65600e546000861461238457601060008781526020019081526020016000205461238d565b601260ff16600a0a5b60405161239b9291906144ec565b60405180910390a35050565b600d5481565b612408600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460126132c4565b61241e6001600f5461332990919063ffffffff16565b600f819055506000600f5490506124398383101560106132c4565b6124f2600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb86866040518363ffffffff1660e01b8152600401612499929190614394565b602060405180830381600087803b1580156124b357600080fd5b505af11580156124c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124eb9190613d91565b60006132c4565b8373ffffffffffffffffffffffffffffffffffffffff167f72debe083e16f39475584adf69a588657185fbd31e7627daa95ed7dbd45b3cc18460405161253891906144d1565b60405180910390a261254f600f54821460146132c4565b50505050565b6125b0600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460136132c4565b6125c66001600f5461332990919063ffffffff16565b600f819055506000600f549050600b548211156125e357600b5491505b6125f882600b546133de90919063ffffffff16565b600b819055506126b7600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040518363ffffffff1660e01b815260040161265e929190614394565b602060405180830381600087803b15801561267857600080fd5b505af115801561268c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b09190613d91565b60006132c4565b8273ffffffffffffffffffffffffffffffffffffffff167f10913cbb30d5b8ffef79cb59f0875923e51b1a5a54fb330d0cb2022e6af8d13483600b546040516127019291906144ec565b60405180910390a2612718600f54821460146132c4565b505050565b612778600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460126132c4565b61278181613461565b50565b6127df600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460126132c4565b6127f2600960010154821115600f6132c4565b61280a816009600101546133de90919063ffffffff16565b6009600101819055507f5b5eb4c315d078b7384bec63e32d19bebdac730f44483dc358bd9085aa20ffb9816009600101546040516128499291906144ec565b60405180910390a150565b6128af600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161460126132c4565b6128bd81831115600d6132c4565b6128d58260096000015461332990919063ffffffff16565b6009600001819055507fa926f60433937c9b276382ddb5204387c2c70104cbe627db98999c7d706c4196826009600001546040516129149291906144ec565b60405180910390a15050565b600080600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638024818a846040518263ffffffff1660e01b815260040161297e91906144d1565b60606040518083038186803b15801561299657600080fd5b505afa1580156129aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce9190613ead565b90506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632eb6534f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612a3a57600080fd5b505afa158015612a4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a729190613f65565b90508082602001511415612c5057612a998260000151600d546133de90919063ffffffff16565b600d81905550600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33866040518363ffffffff1660e01b8152600401612afc9291906142d4565b600060405180830381600087803b158015612b1657600080fd5b505af1158015612b2a573d6000803e3d6000fd5b50505050838573ffffffffffffffffffffffffffffffffffffffff167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca948460000151600b54604051612b7d9291906144ec565b60405180910390a3612c42600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8785600001516040518363ffffffff1660e01b8152600401612be9929190614394565b602060405180830381600087803b158015612c0357600080fd5b505af1158015612c17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3b9190613d91565b60006132c4565b8160000151925050506130cb565b600080836020015114612c7a57601060008460200151815260200190815260200160002054612c84565b670de0b6b3a76400005b905060006010600084815260200190815260200160002054905060008460400151148015612cb3575060008114155b15612ea8576000612cd183866000015161328e90919063ffffffff16565b9050612ce881600e546133de90919063ffffffff16565b600e81905550612d0182826133b190919063ffffffff16565b9550600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33896040518363ffffffff1660e01b8152600401612d609291906142d4565b600060405180830381600087803b158015612d7a57600080fd5b505af1158015612d8e573d6000803e3d6000fd5b50505050868873ffffffffffffffffffffffffffffffffffffffff167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9488600b54604051612ddd9291906144ec565b60405180910390a3612e9e600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a896040518363ffffffff1660e01b8152600401612e45929190614394565b602060405180830381600087803b158015612e5f57600080fd5b505af1158015612e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e979190613d91565b60006132c4565b50505050506130cb565b60006010600086604001518152602001908152602001600020549050612ee46000866040015114158015612edd575060008214155b60056132c4565b612f0d83612eff8388600001516133b190919063ffffffff16565b61328e90919063ffffffff16565b9550600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33896040518363ffffffff1660e01b8152600401612f6c9291906142d4565b600060405180830381600087803b158015612f8657600080fd5b505af1158015612f9a573d6000803e3d6000fd5b50505050612fb386600b546133de90919063ffffffff16565b600b81905550868873ffffffffffffffffffffffffffffffffffffffff167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9488600b546040516130049291906144ec565b60405180910390a36130c5600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a896040518363ffffffff1660e01b815260040161306c929190614394565b602060405180830381600087803b15801561308657600080fd5b505af115801561309a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130be9190613d91565b60006132c4565b50505050505b92915050565b6000613286600d54613278600b5461326a8661325c6131a38a600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016131459190614282565b60206040518083038186803b15801561315d57600080fd5b505afa158015613171573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131959190613f65565b6133b190919063ffffffff16565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016131fe9190614282565b60206040518083038186803b15801561321657600080fd5b505afa15801561322a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061324e9190613f65565b61332990919063ffffffff16565b61332990919063ffffffff16565b6133de90919063ffffffff16565b6133de90919063ffffffff16565b905092915050565b60006132bc826132ae601260ff16600a0a8661351190919063ffffffff16565b61359790919063ffffffff16565b905092915050565b81600760008360158111156132d557fe5b815260200190815260200160002090613324576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161331b9190614454565b60405180910390fd5b505050565b6000808284019050838110156133a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b6000601260ff16600a0a6133ce838561351190919063ffffffff16565b816133d557fe5b04905092915050565b600082821115613456576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b818303905092915050565b6009600001548111156134775760096000015490505b61348f816009600001546133de90919063ffffffff16565b6009600001819055507f21035560539b4b4540708d4273620b634b00bda210e30692ec878ef00741cbc1816009600001546040516134ce9291906144ec565b60405180910390a150565b60006134ed8383601260ff16600a0a613620565b905092915050565b60006135098383601260ff16600a0a61367b565b905092915050565b6000808314156135245760009050613591565b600082840290508284828161353557fe5b041461358c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806148f96021913960400191505060405180910390fd5b809150505b92915050565b600080821161360e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525060200191505060405180910390fd5b81838161361757fe5b04905092915050565b60008061364b8461363d600a86028861351190919063ffffffff16565b61359790919063ffffffff16565b90506005600a828161365957fe5b061061366657600a810190505b600a818161367057fe5b049150509392505050565b600080600a838161368857fe5b0461369c858761351190919063ffffffff16565b816136a357fe5b0490506005600a82816136b257fe5b06106136bf57600a810190505b600a81816136c957fe5b049150509392505050565b6040518060800160405280600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826137325760008555613779565b82601f1061374b57805160ff1916838001178555613779565b82800160010185558215613779579182015b8281111561377857825182559160200191906001019061375d565b5b509050613786919061378a565b5090565b5b808211156137a357600081600090555060010161378b565b5090565b60006137ba6137b58461457d565b61454c565b9050808382526020820190508260005b858110156137fa57813585016137e08882613a3d565b8452602084019350602083019250506001810190506137ca565b5050509392505050565b6000613817613812846145a9565b61454c565b9050808382526020820190508285602086028201111561383657600080fd5b60005b85811015613866578161384c8882613cb0565b845260208401935060208301925050600181019050613839565b5050509392505050565b600061388361387e846145d5565b61454c565b90508281526020810184848401111561389b57600080fd5b6138a68482856147a8565b509392505050565b6000813590506138bd816147cd565b92915050565b600082601f8301126138d457600080fd5b81356138e48482602086016137a7565b91505092915050565b600082601f8301126138fe57600080fd5b815161390e848260208601613804565b91505092915050565b600081519050613926816147e4565b92915050565b60008135905061393b816147fb565b92915050565b600081519050613950816147fb565b92915050565b60008135905061396581614812565b92915050565b60008151905061397a81614812565b92915050565b60008135905061398f81614829565b92915050565b6000813590506139a481614840565b92915050565b6000813590506139b981614857565b92915050565b6000813590506139ce8161486e565b92915050565b6000813590506139e381614885565b92915050565b6000813590506139f88161489c565b92915050565b600081359050613a0d816148b3565b92915050565b600081519050613a22816148b3565b92915050565b600081519050613a37816148ca565b92915050565b600082601f830112613a4e57600080fd5b8135613a5e848260208601613870565b91505092915050565b600060608284031215613a7957600080fd5b613a83606061454c565b90506000613a9384828501613cb0565b6000830152506020613aa784828501613cb0565b6020830152506040613abb84828501613cb0565b60408301525092915050565b600060e08284031215613ad957600080fd5b613ae360e061454c565b90506000613af384828501613c9b565b6000830152506020613b078482850161392c565b6020830152506040613b1b8482850161392c565b6040830152506060613b2f848285016139fe565b6060830152506080613b4384828501613956565b60808301525060a0613b5784828501613c9b565b60a08301525060c0613b6b84828501613c9b565b60c08301525092915050565b600060e08284031215613b8957600080fd5b613b9360e061454c565b90506000613ba384828501613cb0565b6000830152506020613bb784828501613941565b6020830152506040613bcb84828501613941565b6040830152506060613bdf84828501613a13565b6060830152506080613bf38482850161396b565b60808301525060a0613c0784828501613cb0565b60a08301525060c0613c1b84828501613cb0565b60c08301525092915050565b600060808284031215613c3957600080fd5b613c43608061454c565b90506000613c5384828501613c9b565b6000830152506020613c6784828501613c9b565b6020830152506040613c7b84828501613c9b565b6040830152506060613c8f84828501613c9b565b60608301525092915050565b600081359050613caa816148e1565b92915050565b600081519050613cbf816148e1565b92915050565b60008060408385031215613cd857600080fd5b6000613ce6858286016138ae565b9250506020613cf785828601613c9b565b9150509250929050565b600080600060608486031215613d1657600080fd5b6000613d24868287016138ae565b9350506020613d3586828701613c9b565b9250506040613d4686828701613c9b565b9150509250925092565b600060208284031215613d6257600080fd5b600082015167ffffffffffffffff811115613d7c57600080fd5b613d88848285016138ed565b91505092915050565b600060208284031215613da357600080fd5b6000613db184828501613917565b91505092915050565b600080600080600080600080610100898b031215613dd757600080fd5b6000613de58b828c016139aa565b9850506020613df68b828c016139bf565b9750506040613e078b828c01613995565b9650506060613e188b828c016139d4565b9550506080613e298b828c016139e9565b94505060a0613e3a8b828c01613980565b93505060c0613e4b8b828c01613980565b92505060e089013567ffffffffffffffff811115613e6857600080fd5b613e748b828c016138c3565b9150509295985092959890939650565b600060208284031215613e9657600080fd5b6000613ea484828501613a28565b91505092915050565b600060608284031215613ebf57600080fd5b6000613ecd84828501613a67565b91505092915050565b600060e08284031215613ee857600080fd5b6000613ef684828501613b77565b91505092915050565b6000806101008385031215613f1357600080fd5b6000613f2185828601613ac7565b92505060e0613f3285828601613c9b565b9150509250929050565b600060208284031215613f4e57600080fd5b6000613f5c84828501613c9b565b91505092915050565b600060208284031215613f7757600080fd5b6000613f8584828501613cb0565b91505092915050565b60008060408385031215613fa157600080fd5b6000613faf85828601613c9b565b9250506020613fc085828601613956565b9150509250929050565b60008060006101808486031215613fe057600080fd5b6000613fee86828701613c9b565b9350506020613fff86828701613ac7565b92505061010061401186828701613c27565b9150509250925092565b6000806040838503121561402e57600080fd5b600061403c85828601613c9b565b925050602061404d85828601613c9b565b9150509250929050565b60008060006060848603121561406c57600080fd5b600061407a86828701613c9b565b935050602061408b86828701613c9b565b925050604061409c86828701613c9b565b9150509250925092565b6140af8161472a565b82525050565b6140be8161462b565b82525050565b6140cd81614649565b82525050565b6140dc8161473c565b82525050565b6140eb81614760565b82525050565b6140fa81614772565b82525050565b60008154600181166000811461411d576001811461414357614187565b607f600283041661412e818761461a565b955060ff198316865260208601935050614187565b60028204614151818761461a565b955061415c85614605565b60005b8281101561417e5781548189015260018201915060208101905061415f565b80880195505050505b505092915050565b600061419c60138361461a565b91507f616c726561647920696e697469616c697a6564000000000000000000000000006000830152602082019050919050565b60006141dc600f8361461a565b91507f6572726f72206d736720636f756e7400000000000000000000000000000000006000830152602082019050919050565b6080820160008201516142256000850182614264565b5060208201516142386020850182614264565b50604082015161424b6040850182614264565b50606082015161425e6060850182614264565b50505050565b61426d81614720565b82525050565b61427c81614720565b82525050565b600060208201905061429760008301846140b5565b92915050565b60006060820190506142b260008301866140a6565b6142bf60208301856140b5565b6142cc6040830184614273565b949350505050565b60006040820190506142e960008301856140a6565b6142f66020830184614273565b9392505050565b600060608201905061431260008301866140a6565b61431f6020830185614273565b61432c60408301846140f1565b949350505050565b600060608201905061434960008301866140a6565b6143566020830185614273565b6143636040830184614273565b949350505050565b600060408201905061438060008301856140b5565b61438d60208301846140e2565b9392505050565b60006040820190506143a960008301856140b5565b6143b66020830184614273565b9392505050565b60006060820190506143d260008301866140b5565b6143df6020830185614273565b6143ec6040830184614273565b949350505050565b600060608201905061440960008301866140c4565b6144166020830185614273565b61442360408301846140c4565b949350505050565b600060408201905061444060008301856140d3565b61444d6020830184614273565b9392505050565b6000602082019050818103600083015261446e8184614100565b905092915050565b6000602082019050818103600083015261448f8161418f565b9050919050565b600060208201905081810360008301526144af816141cf565b9050919050565b60006080820190506144cb600083018461420f565b92915050565b60006020820190506144e66000830184614273565b92915050565b60006040820190506145016000830185614273565b61450e6020830184614273565b9392505050565b600060608201905061452a6000830186614273565b6145376020830185614273565b6145446040830184614273565b949350505050565b6000604051905081810181811067ffffffffffffffff82111715614573576145726147b7565b5b8060405250919050565b600067ffffffffffffffff821115614598576145976147b7565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156145c4576145c36147b7565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156145f0576145ef6147b7565b5b601f19601f8301169050602081019050919050565b60008190508160005260206000209050919050565b600082825260208201905092915050565b600061463682614700565b9050919050565b60008115159050919050565b6000819050919050565b600061465e8261462b565b9050919050565b60006146708261462b565b9050919050565b60006146828261462b565b9050919050565b60006146948261462b565b9050919050565b60006146a68261462b565b9050919050565b60006146b88261462b565b9050919050565b60006146ca8261462b565b9050919050565b60006146dc8261462b565b9050919050565b60008190506146f1826147b9565b919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061473582614784565b9050919050565b60006147478261474e565b9050919050565b600061475982614700565b9050919050565b600061476b826146e3565b9050919050565b600061477d82614720565b9050919050565b600061478f82614796565b9050919050565b60006147a182614700565b9050919050565b82818337600083830152505050565bfe5b600381106147ca576147c96147b7565b5b50565b6147d68161462b565b81146147e157600080fd5b50565b6147ed8161463d565b81146147f857600080fd5b50565b61480481614649565b811461480f57600080fd5b50565b61481b81614653565b811461482657600080fd5b50565b61483281614665565b811461483d57600080fd5b50565b61484981614677565b811461485457600080fd5b50565b61486081614689565b811461486b57600080fd5b50565b6148778161469b565b811461488257600080fd5b50565b61488e816146ad565b811461489957600080fd5b50565b6148a5816146bf565b81146148b057600080fd5b50565b6148bc816146d1565b81146148c757600080fd5b50565b6148d3816146f6565b81146148de57600080fd5b50565b6148ea81614720565b81146148f557600080fd5b5056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220e301030e340c9f644c9049bacad162f446183648286340d7c3e31a1b8388646164736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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