Contract 0x2935cd347b79c319a6464fe3b1087170f142418c 2

Lyra 
 

Contract Overview

Lyra: ETH Liquidity Pool
Balance:
0 Ether

EtherValue:
$0.00

Token:
Txn Hash Method
Index
From
To
Value
0x2b1cc8a5d00594653dd76791b275f132f27a942f5ce44c0986656888cfe30563Withdraw261507892022-09-29 3:32:0311 hrs 42 mins ago0x084352811a2b4e9eb518b36d119bbe4d0c4fefcb IN  Lyra: ETH Liquidity Pool0 Ether0.000033457280.00100155
0x7c1e404016954f0501e017144d29d1b56dee770ca4477b4f7957d854b6b3ee57Withdraw256083132022-09-26 17:11:242 days 22 hrs ago0xb71fe36e2c81138746e6a8fe3731aa373c93b8bd IN  Lyra: ETH Liquidity Pool0 Ether0.0000845415230.00100155
0xdb2696e3b435d367168de6cfd436e6df6b94fcfa506c8f5b3012d4d1f9518811Withdraw256076962022-09-26 17:05:532 days 22 hrs ago0xb71fe36e2c81138746e6a8fe3731aa373c93b8bd IN  Lyra: ETH Liquidity Pool0 Ether0.0000978911710.00100155
0x27ddd277627037b39f65b17e317d57784d2ca17c755017a2ddd2ae5f1d5f93ddWithdraw255477942022-09-26 12:06:243 days 3 hrs ago 0x1178463f809657513bfaa2bb69dbef55d9f61e9d IN  Lyra: ETH Liquidity Pool0 Ether0.0000193387020.00100155
0x64d10ee314333cb8234aa783dc472754adce8d348709d28948ac4b697e047071Withdraw254953792022-09-26 7:45:173 days 7 hrs ago0xd8263b8b277c7df352f1851923125a07a6982540 IN  Lyra: ETH Liquidity Pool0 Ether0.0000195485050.00100155
0xcb6764d7dc0b1149ef4b154bf6e48707661392134c076d1c0dfd24aae3f0a933Withdraw254274402022-09-26 0:38:353 days 14 hrs ago0x18e9664a094d8d134bb3bae84119305afe308ece IN  Lyra: ETH Liquidity Pool0 Ether0.0000197906450.00100155
0x3059d634a5bd7fa6bcf94362e418891e4ea4240ae83c74ff43ff29c2c52ce18fWithdraw253569802022-09-25 15:43:483 days 23 hrs ago0xc90bfb542e4d570f4e9ff83d0d6766b2ed3a557f IN  Lyra: ETH Liquidity Pool0 Ether0.0000409560870.00100155
0x89b8ab49fdd0bbc5674ff32cc269555d7b7aceee646dc221fff8552810607798Withdraw253483082022-09-25 14:54:384 days 19 mins ago0x32dbc2201d6804b743e353fbbcc767598ba56901 IN  Lyra: ETH Liquidity Pool0 Ether0.0000289673140.00100155
0xaa9a8ee29bda1628ae97c23fab639f5b062d2d3fcbb208740aa254570928091bWithdraw253482332022-09-25 14:54:084 days 20 mins ago0x32dbc2201d6804b743e353fbbcc767598ba56901 IN  Lyra: ETH Liquidity Pool0 Ether0.0000289721210.00100155
0x0e610a5bd44813a27905ba63916fd348f93632f434b64a4547cd93a6446401f3Withdraw253481422022-09-25 14:53:384 days 20 mins ago0x32dbc2201d6804b743e353fbbcc767598ba56901 IN  Lyra: ETH Liquidity Pool0 Ether0.0000289721210.00100155
0xd1e4acb98e776b4479079a6ea9009edc39b8459d048e6a634c8d248af93e6021Withdraw251769512022-09-24 19:56:134 days 19 hrs ago 0x6d82555523d044e3710ee79d40a54d335cdf1261 IN  Lyra: ETH Liquidity Pool0 Ether0.0000137577360.0013
0x5f10126b3c223f2f93d3265ec76785714d71e3879e66fe431f4ba2f4b58e0235Withdraw251297942022-09-24 14:20:075 days 54 mins ago0xf8f74902ca4322b5dc2fca74d711eeb835e106d3 IN  Lyra: ETH Liquidity Pool0 Ether0.0000201956470.00100155
0xb3e4505c0256b4daff4d7ed7872561afeb9500edb044f1e53b02f7137173952eWithdraw251000302022-09-24 11:53:455 days 3 hrs ago0x2dcd5c2591b6617ca91b6654ea3939213dab7c38 IN  Lyra: ETH Liquidity Pool0 Ether0.0000210511740.00100155
0xcc4757d143d19380eaae85b63d32af6bdf26b4fc73739a02d91112ee1f88ea19Withdraw249487882022-09-23 19:18:305 days 19 hrs ago0x7b1768877a8cb5f51adb4c231626dae8f862f881 IN  Lyra: ETH Liquidity Pool0 Ether0.0000287136920.00100155
0xb31cc9658c83803f4c2ce36e5f043295dd8f2f2c61fd21227f0a0b062ffeadb5Withdraw248119592022-09-23 9:48:126 days 5 hrs ago0x1f92bedf0bc827fc3abb1a9c3f0f3a5bf8d84ab6 IN  Lyra: ETH Liquidity Pool0 Ether0.0000303260980.00100155
0x0df9488faee055ef55976e6c6291492c1f7f6f4f5e5ae7faf9cfaf79ccb72c01Withdraw246513312022-09-22 21:44:006 days 17 hrs ago 0x2a693ccbda744faf14ecb7c28bd811927bea61a7 IN  Lyra: ETH Liquidity Pool0 Ether0.0000322760760.00100155
0x67168783d21aa7cc95d89cd8c0511ee5b12e18c57857f4e2aa5cd0d3263c6bf5Withdraw245962072022-09-22 15:51:406 days 23 hrs ago0x8c302250f1f5f4a933b7a62b52e998b0a40c3917 IN  Lyra: ETH Liquidity Pool0 Ether0.0000764635850.00100155
0x423510e7eb53ef22d17c692a18737273c3225926ae51ad8f8e2f10bf3a292b84Withdraw245893962022-09-22 15:16:056 days 23 hrs ago0x48412d4e8d1ca28edfeddd5fbae128cbf84c7e5f IN  Lyra: ETH Liquidity Pool0 Ether0.00015627810.00100155
0x723c1d993df4b6b8510bac4c4e6c1c2b7e27334ed0cb4a0052cca507f27549f0Withdraw245888982022-09-22 15:13:017 days 1 min ago0x9345c48c1dbcf90b73a095a261cd7777aff6d8e5 IN  Lyra: ETH Liquidity Pool0 Ether0.0001584481850.00100155
0x6fc6c187ee1c4029eed4ce272fa8fa40089e2cf029206d5fd7fb4288ac5719d2Withdraw245883302022-09-22 15:10:147 days 4 mins ago0x686d26d709a11f4da840f4fc4b14b94fed5f90c7 IN  Lyra: ETH Liquidity Pool0 Ether0.0001330224270.00100155
0xb4356188d66a9df0c5a956914d5220834f38919d91ff11de4010afedfdd57908Withdraw245876512022-09-22 15:07:147 days 7 mins ago0x7d23bc8da7fb9fa49af7d74db3328e7970452a28 IN  Lyra: ETH Liquidity Pool0 Ether0.0001307729930.00100155
0xd4c3d22134c7d16740658b859a9cc5872da1cf6b979fbff3bbdc85f926322472Withdraw245871152022-09-22 15:05:297 days 9 mins ago0xddd6578efdf7a516dc13487d38720947bb225da6 IN  Lyra: ETH Liquidity Pool0 Ether0.0001173889890.00100155
0x45f958b66366c44b66c74269c62f19ad24865ae33e868c7da02917646fd367b7Withdraw245865482022-09-22 15:03:147 days 11 mins ago0x916766e8259e05eb941abcdecb3dc79aa72e16cc IN  Lyra: ETH Liquidity Pool0 Ether0.0001051248660.00100155
0xd3ba89ac08df24e12ffdf935d59166ebeea4a48d72ee7e07993b72f23b524dc6Withdraw245860012022-09-22 15:00:417 days 13 mins ago0x3883694454d4afa41b30e8bcf2c1810139d7348e IN  Lyra: ETH Liquidity Pool0 Ether0.0000810285570.00100155
0xac74de01577f4ad34dfe615c4eb7b8b36a5f6502dd50d91b8ebf754b6bbd172eWithdraw245851782022-09-22 14:57:397 days 16 mins ago0x1b1f457238c422d97d231ac10137aafd4b9a3703 IN  Lyra: ETH Liquidity Pool0 Ether0.000061343410.00100155
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x7c1e404016954f0501e017144d29d1b56dee770ca4477b4f7957d854b6b3ee57256083132022-09-26 17:11:242 days 22 hrs ago Lyra: ETH Liquidity PoolSynthetix: sUSD Token0 Ether
0x7c1e404016954f0501e017144d29d1b56dee770ca4477b4f7957d854b6b3ee57256083132022-09-26 17:11:242 days 22 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0x7c1e404016954f0501e017144d29d1b56dee770ca4477b4f7957d854b6b3ee57256083132022-09-26 17:11:242 days 22 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Option Market0 Ether
0x7c1e404016954f0501e017144d29d1b56dee770ca4477b4f7957d854b6b3ee57256083132022-09-26 17:11:242 days 22 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0xdb2696e3b435d367168de6cfd436e6df6b94fcfa506c8f5b3012d4d1f9518811256076962022-09-26 17:05:532 days 22 hrs ago Lyra: ETH Liquidity PoolSynthetix: sUSD Token0 Ether
0xdb2696e3b435d367168de6cfd436e6df6b94fcfa506c8f5b3012d4d1f9518811256076962022-09-26 17:05:532 days 22 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0xdb2696e3b435d367168de6cfd436e6df6b94fcfa506c8f5b3012d4d1f9518811256076962022-09-26 17:05:532 days 22 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Option Market0 Ether
0xdb2696e3b435d367168de6cfd436e6df6b94fcfa506c8f5b3012d4d1f9518811256076962022-09-26 17:05:532 days 22 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0x27ddd277627037b39f65b17e317d57784d2ca17c755017a2ddd2ae5f1d5f93dd255477942022-09-26 12:06:243 days 3 hrs ago Lyra: ETH Liquidity PoolSynthetix: sUSD Token0 Ether
0x27ddd277627037b39f65b17e317d57784d2ca17c755017a2ddd2ae5f1d5f93dd255477942022-09-26 12:06:243 days 3 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0x27ddd277627037b39f65b17e317d57784d2ca17c755017a2ddd2ae5f1d5f93dd255477942022-09-26 12:06:243 days 3 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Option Market0 Ether
0x27ddd277627037b39f65b17e317d57784d2ca17c755017a2ddd2ae5f1d5f93dd255477942022-09-26 12:06:243 days 3 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0x64d10ee314333cb8234aa783dc472754adce8d348709d28948ac4b697e047071254953792022-09-26 7:45:173 days 7 hrs ago Lyra: ETH Liquidity PoolSynthetix: sUSD Token0 Ether
0x64d10ee314333cb8234aa783dc472754adce8d348709d28948ac4b697e047071254953792022-09-26 7:45:173 days 7 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0x64d10ee314333cb8234aa783dc472754adce8d348709d28948ac4b697e047071254953792022-09-26 7:45:173 days 7 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Option Market0 Ether
0x64d10ee314333cb8234aa783dc472754adce8d348709d28948ac4b697e047071254953792022-09-26 7:45:173 days 7 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0xcb6764d7dc0b1149ef4b154bf6e48707661392134c076d1c0dfd24aae3f0a933254274402022-09-26 0:38:353 days 14 hrs ago Lyra: ETH Liquidity PoolSynthetix: sUSD Token0 Ether
0xcb6764d7dc0b1149ef4b154bf6e48707661392134c076d1c0dfd24aae3f0a933254274402022-09-26 0:38:353 days 14 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0xcb6764d7dc0b1149ef4b154bf6e48707661392134c076d1c0dfd24aae3f0a933254274402022-09-26 0:38:353 days 14 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Option Market0 Ether
0xcb6764d7dc0b1149ef4b154bf6e48707661392134c076d1c0dfd24aae3f0a933254274402022-09-26 0:38:353 days 14 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0x3059d634a5bd7fa6bcf94362e418891e4ea4240ae83c74ff43ff29c2c52ce18f253569802022-09-25 15:43:483 days 23 hrs ago Lyra: ETH Liquidity PoolSynthetix: sUSD Token0 Ether
0x3059d634a5bd7fa6bcf94362e418891e4ea4240ae83c74ff43ff29c2c52ce18f253569802022-09-25 15:43:483 days 23 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0x3059d634a5bd7fa6bcf94362e418891e4ea4240ae83c74ff43ff29c2c52ce18f253569802022-09-25 15:43:483 days 23 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Option Market0 Ether
0x3059d634a5bd7fa6bcf94362e418891e4ea4240ae83c74ff43ff29c2c52ce18f253569802022-09-25 15:43:483 days 23 hrs ago Lyra: ETH Liquidity Pool Lyra: ETH Liquidity Certificate0 Ether
0x89b8ab49fdd0bbc5674ff32cc269555d7b7aceee646dc221fff8552810607798253483082022-09-25 14:54:384 days 19 mins ago Lyra: ETH Liquidity PoolSynthetix: sUSD Token0 Ether
[ Download CSV Export 
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

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