Contract 0x5da5b71b88c42544b642d4ab781b30831edac341

 
 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xd0237abb79fc2fd6c2d4e77ed5430c1f437926739eea4884ef9ffbc569146a9cBurn LP92019652021-07-16 8:23:56195 days 23 hrs ago0x61f9eb484dcc0ca3f31720f761d785d6b461adf6 IN  0x5da5b71b88c42544b642d4ab781b30831edac3410 BNB0.00059732
0xc29674ba256149b74270c1ec89e1c6ffbbda19bf2d5a4aea9a5c090b05b56f53Burn LP92012142021-07-16 7:46:11196 days 21 mins ago0x61f9eb484dcc0ca3f31720f761d785d6b461adf6 IN  0x5da5b71b88c42544b642d4ab781b30831edac3410 BNB0.00029824
0xfeaba15434ea12f89e8437d31b8e302e9134cd16ad19e9299d4a1c61dd8171f0Burn LP90059692021-07-09 13:02:00202 days 19 hrs ago0x61f9eb484dcc0ca3f31720f761d785d6b461adf6 IN  0x5da5b71b88c42544b642d4ab781b30831edac3410 BNB0.00029824
0x437dcee9c148b59a589a9bb1b141ee023aef71ba2e6b4cfb1e3b949a2332f9deSet Owner88989252021-07-05 19:36:20206 days 12 hrs agoMetahero: Deployer IN  0x5da5b71b88c42544b642d4ab781b30831edac3410 BNB0.000152955
0xb36b05cf20bfed2b8448bb86e809f71853ddc1696c594d4c91f190da53b80947Initialize88947432021-07-05 16:05:53206 days 16 hrs agoMetahero: Deployer IN  0x5da5b71b88c42544b642d4ab781b30831edac3410 BNB0.03394338
0x45a28707a1db1b88428501892eab88ef0fc1c5a88676ee928eadfbd5b4ca0f7a0x6080604088947352021-07-05 16:05:28206 days 16 hrs agoMetahero: Deployer IN  Create: MetaheroLPMForUniswapV20 BNB0.02579789
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MetaheroLPMForUniswapV2

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 17 : MetaheroLPMForUniswapV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

import "./core/erc20/IWrappedNative.sol";
import "./uniswapV2/IUniswapV2Factory.sol";
import "./uniswapV2/IUniswapV2Pair.sol";
import "./uniswapV2/IUniswapV2Router02.sol";
import "./MetaheroLPM.sol";


/**
 * @title Metahero liquidity pool manager for Uniswap v2
 *
 * @author Stanisław Głogowski <[email protected]>
 */
contract MetaheroLPMForUniswapV2 is MetaheroLPM {
  struct Settings {
    uint256 enableBurnLPAtValue; // value of the tokens that turned on the burnLP method
    address stableCoin; // stable coin address eg. BUSD, DAI
  }

  /**
   * @return settings object
   */
  Settings public settings;

  /**
   * @return Uniswap V2 factory address
   */
  IUniswapV2Factory public uniswapFactory;

  /**
   * @return Uniswap V2 pair address
   */
  IUniswapV2Pair public uniswapPair;

  /**
   * @return Uniswap V2 router02 address
   */
  IUniswapV2Router02 public uniswapRouter;

  IWrappedNative private wrappedNative;
  bool private correctPairOrder;

  // events

  /**
   * @dev Emitted the contract is initialized
   * @param enableBurnLPAtValue value of the tokens that turned on the burnLP method
   * @param stableCoin stable coin address eg. BUSD, DAI
   * @param token token address
   * @param uniswapRouter Uniswap V2 router02 address
   * @param uniswapPair Uniswap V2 pair address
   */
  event Initialized(
    uint256 enableBurnLPAtValue,
    address stableCoin,
    address token,
    address uniswapRouter,
    address uniswapPair
  );

  /**
   * @dev Public constructor
   */
  constructor ()
    public
    MetaheroLPM()
  {
    //
  }

  // external functions

  /**
   * @dev Mints stable coins to the contract
   */
  receive()
    external
    payable
  {
    _deposit(msg.value);
  }

  /**
   * @dev Mints stable coins to the contract
   */
  function deposit()
    external
    payable
  {
    _deposit(msg.value);
  }

  /**
   * @dev Initializes the contract
   * @param enableBurnLPAtValue value of the tokens that turned on the burnLP method
   * @param stableCoin stable coin address eg. BUSD, DAI
   * @param token_ token address
   * @param uniswapRouter_ Uniswap V2 router02 address
   */
  function initialize(
    uint256 enableBurnLPAtValue,
    address stableCoin,
    address token_,
    address uniswapRouter_
  )
    external
    onlyInitializer
  {
    _initialize(token_);

    if (enableBurnLPAtValue != 0) {
      require(
        stableCoin != address(0),
        "MetaheroLPMForUniswapV2#2" // stable coin is the zero address
      );

      settings.enableBurnLPAtValue = enableBurnLPAtValue;
      settings.stableCoin = stableCoin;
    }

    require(
      uniswapRouter_ != address(0),
      "MetaheroLPMForUniswapV2#3" // Uniswap V2 router02 is the zero address
    );

    uniswapRouter = IUniswapV2Router02(uniswapRouter_);
    uniswapFactory = IUniswapV2Factory(uniswapRouter.factory());

    wrappedNative = IWrappedNative(uniswapRouter.WETH());

    // create a pair
    uniswapPair = IUniswapV2Pair(uniswapFactory.createPair(
      address(token),
      address(wrappedNative)
    ));

    correctPairOrder = address(token) < address(wrappedNative);

    emit Initialized(
      enableBurnLPAtValue,
      stableCoin,
      token_,
      uniswapRouter_,
      address(uniswapPair)
    );
  }

  // external functions (views)

  /**
   * @notice Checks when to sync the liquidity pool
   * @param sender sender address
   * @param recipient recipient address
   */
  function canSyncLP(
    address sender,
    address recipient
  )
    external
    view
    override
    returns (
      bool shouldSyncLPBefore,
      bool shouldSyncLPAfter
    )
  {
    if (sender != address(uniswapPair)) { // omit when swap HERO > BNB
      if (recipient == address(uniswapPair)) {
        shouldSyncLPBefore = true; // swap BNB > HERO
      } else {
        shouldSyncLPAfter = true;
      }
    }

    return (shouldSyncLPBefore, shouldSyncLPAfter);
  }

  // internal functions

  function _syncLP()
    internal
    override
  {
    uint256 totalAmount = token.balanceOf(address(this));

    if (totalAmount >= 2) {
      uint256 swapAmount = totalAmount.div(2);
      uint256 liquidityAmount = totalAmount.sub(swapAmount);

      // swap half for native
      _swapTokens(swapAmount);

      // add other half with received native
      _addTokensToLiquidity(liquidityAmount);
    }
  }

  function _burnLP(
    uint256 amount
  )
    internal
    override
  {
    if (settings.enableBurnLPAtValue != 0) {
      (uint256 tokenReserve, ) = _getLiquidityReserves();

      require(
        tokenReserve != 0,
        "MetaheroLPMForUniswapV2#4" // token reserve is zero
      );

      require(
        amount <= tokenReserve,
        "MetaheroLPMForUniswapV2#5" // amount higher than token reserve
      );

      uint256 tokenReserveValue = _calcTokensValue(tokenReserve);

      require(
        tokenReserveValue > settings.enableBurnLPAtValue,
        "MetaheroLPMForUniswapV2#6" // burnLP disabled
      );

      uint256 amountValue = _calcTokensValue(amount);
      uint256 maxAmountValue = tokenReserveValue.sub(settings.enableBurnLPAtValue);

      require(
        amountValue <= maxAmountValue,
        "MetaheroLPMForUniswapV2#7" // amount is too high
      );
    }

    // remove liquidity
    _removeLiquidity();

    uint256 totalAmount = token.balanceOf(address(this));

    require(
      totalAmount >= amount,
      "MetaheroLPMForUniswapV2#8" // amount is too high
    );

    token.burn(amount); // burn tokens

    _addTokensToLiquidity( // adds others to liquidity
      totalAmount.sub(amount)
    );
  }

  // private functions

  function _deposit(
    uint256 amount
  )
    private
  {
    require(
      amount != 0,
      "MetaheroLPMForUniswapV2#1" // amount is zero
    );

    wrappedNative.deposit{value: amount}();
  }

  function _swapTokens(
    uint256 amount
  )
    private
  {
    token.approve(
      address(uniswapRouter),
      amount
    );

    address[] memory path = new address[](2);

    path[0] = address(token);
    path[1] = address(wrappedNative);

    // omit revert, let's use those tokens on the next swap
    try uniswapRouter.swapExactTokensForTokens(
      amount,
      0,
      path,
      address(this),
      block.timestamp // solhint-disable-line not-rely-on-time
    ) {
      //
    } catch {
      //
    }
  }

  function _addTokensToLiquidity(
    uint256 tokensAmount
  )
    private
  {
    uint256 wrappedNativeAmount = wrappedNative.balanceOf(address(this));

    if (
      tokensAmount != 0 &&
      wrappedNativeAmount != 0
    ) {
      token.approve(
        address(uniswapRouter),
        tokensAmount
      );

      wrappedNative.approve(
        address(uniswapRouter),
        wrappedNativeAmount
      );

      // omit revert, let's use those tokens on the next swap
      try uniswapRouter.addLiquidity(
        address(token),
        address(wrappedNative),
        tokensAmount,
        wrappedNativeAmount,
        0,
        0,
        address(this),
        block.timestamp // solhint-disable-line not-rely-on-time
      ) {
        //
      } catch {
        //
      }
    }
  }

  function _removeLiquidity()
    private
  {
    uint256 liquidity = uniswapPair.balanceOf(address(this));

    if (liquidity != 0) {
      uniswapPair.approve(
        address(uniswapRouter),
        liquidity
      );

      uniswapRouter.removeLiquidity(
        address(token),
        address(wrappedNative),
        liquidity,
        0,
        0,
        address(this),
        block.timestamp // solhint-disable-line not-rely-on-time
      );
    }
  }

  // private functions (views)

  function _calcTokensValue(
    uint256 amount
  )
    private
    view
    returns (uint256)
  {
    address[] memory path = new address[](3);

    path[0] = address(token);
    path[1] = address(wrappedNative);
    path[2] = settings.stableCoin;

    uint256[] memory amounts = uniswapRouter.getAmountsOut(amount, path);

    return amounts[2];
  }

  function _getLiquidityReserves()
    private
    view
    returns (
      uint256 tokenReserve,
      uint256 wrappedNativeReserve
    )
  {
    (
      uint112 reserve0,
      uint112 reserve1,
    ) = uniswapPair.getReserves();

    (tokenReserve, wrappedNativeReserve) = correctPairOrder
      ? (reserve0, reserve1)
      : (reserve1, reserve0);

    return (tokenReserve, wrappedNativeReserve);
  }
}

File 2 of 17 : IWrappedNative.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.12;

import "./IERC20.sol";


/**
 * @title Wrapped native (eg. WBNB, WETH) token interface
 *
 * @notice Based on https://github.com/Uniswap/uniswap-v2-periphery/blob/dda62473e2da448bc9cb8f4514dadda4aeede5f4/contracts/interfaces/IWETH.sol
 */
interface IWrappedNative is IERC20 {
  // external functions

  function deposit()
    external
    payable;

  function withdraw(
    uint256 amount
  )
    external;
}

File 3 of 17 : IUniswapV2Factory.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.12;

/**
 * @title Uniswap v2 factory interface
 *
 * @notice Based on https://github.com/Uniswap/uniswap-v2-core/blob/4dd59067c76dea4a0e8e4bfdda41877a6b16dedc/contracts/interfaces/IUniswapV2Factory.sol
 */
interface IUniswapV2Factory {
  // events

  event PairCreated(
    address indexed token0,
    address indexed token1,
    address pair,
    uint256
  );

  // external functions

  function createPair(
    address tokenA,
    address tokenB
  )
    external
    returns (address);

  function setFeeTo(
    address
  )
    external;

  function setFeeToSetter(
    address
  )
    external;

  // external functions (views)

  function feeTo()
    external
    view
    returns (address);

  function feeToSetter()
    external
    view
    returns (address);

  function getPair(
    address tokenA,
    address tokenB
  )
    external
    view
    returns (address);

  function allPairs(
    uint256
  )
    external
    view
    returns (address);

  function allPairsLength()
    external
    view
    returns (uint256);
}

File 4 of 17 : IUniswapV2Pair.sol
// SPDX-License-Identifier: GPL-3.0
/* solhint-disable func-name-mixedcase */
pragma solidity ^0.6.12;

import "../core/erc20/IERC20.sol";


/**
 * @title Uniswap V2 pair interface
 *
 * @notice Based on https://github.com/Uniswap/uniswap-v2-core/blob/4dd59067c76dea4a0e8e4bfdda41877a6b16dedc/contracts/interfaces/IUniswapV2Pair.sol
 */
interface IUniswapV2Pair is IERC20 {
  // events

  event Mint(
    address indexed sender,
    uint256 amount0,
    uint256 amount1
  );

  event Burn(
    address indexed sender,
    uint256 amount0,
    uint256 amount1,
    address indexed to
  );

  event Swap(
    address indexed sender,
    uint256 amount0In,
    uint256 amount1In,
    uint256 amount0Out,
    uint256 amount1Out,
    address indexed to
  );

  event Sync(
    uint112 reserve0,
    uint112 reserve1
  );

  // external functions

  function initialize(
    address,
    address
  )
    external;

  function mint(
    address to
  )
    external
    returns (uint256);

  function burn(
    address to
  )
    external
    returns (uint256, uint256);

  function swap(
    uint256 amount0Out,
    uint256 amount1Out,
    address to,
    bytes calldata data
  )
    external;

  function skim(
    address to
  )
    external;

  function sync()
    external;

  function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  )
    external;

  // external functions (views)

  function DOMAIN_SEPARATOR()
    external
    view
    returns (bytes32);

  function nonces(
    address owner
  )
    external
    view
    returns (uint256);

  function factory()
    external
    view
    returns (address);

  function token0()
    external
    view
    returns (address);

  function token1()
    external
    view
    returns (address);

  function getReserves()
    external
    view
    returns (uint112, uint112, uint32);

  function price0CumulativeLast()
    external
    view
    returns (uint256);

  function price1CumulativeLast()
    external
    view
    returns (uint256);

  function kLast()
    external
    view
    returns (uint256);

  // external functions (pure)

  function PERMIT_TYPEHASH()
    external
    pure
    returns (bytes32);

  function MINIMUM_LIQUIDITY()
    external
    pure
    returns (uint256);
}

File 5 of 17 : IUniswapV2Router02.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.12;

import "./IUniswapV2Router01.sol";


/**
 * @title Uniswap V2 router02 interface
 *
 * @notice Based on https://github.com/Uniswap/uniswap-v2-periphery/blob/dda62473e2da448bc9cb8f4514dadda4aeede5f4/contracts/interfaces/IUniswapV2Router02.sol
 */
interface IUniswapV2Router02 is IUniswapV2Router01 {
  // external functions

  function swapExactETHForTokensSupportingFeeOnTransferTokens(
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external
    payable;

  function removeLiquidityETHSupportingFeeOnTransferTokens(
    address token,
    uint256 liquidity,
    uint256 amountTokenMin,
    uint256 amountETHMin,
    address to,
    uint256 deadline
  )
    external
    returns (uint256);

  function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
    address token,
    uint256 liquidity,
    uint256 amountTokenMin,
    uint256 amountETHMin,
    address to,
    uint256 deadline,
    bool approveMax,
    uint8 v,
    bytes32 r,
    bytes32 s
  )
    external
    returns (uint256);

  function swapExactTokensForTokensSupportingFeeOnTransferTokens(
    uint256 amountIn,
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external;

  function swapExactTokensForETHSupportingFeeOnTransferTokens(
    uint256 amountIn,
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external;
}

File 6 of 17 : MetaheroLPM.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

import "./core/access/Lockable.sol";
import "./core/access/Owned.sol";
import "./core/lifecycle/Initializable.sol";
import "./core/math/SafeMathLib.sol";
import "./MetaheroToken.sol";


/**
 * @title Metahero abstract liquidity pool manager
 *
 * @author Stanisław Głogowski <[email protected]>
 */
abstract contract MetaheroLPM is Lockable, Owned, Initializable {
  using SafeMathLib for uint256;

  /**
   * @return token address
   */
  MetaheroToken public token;

  // modifiers

  /**
   * @dev Throws if msg.sender is not the token
   */
  modifier onlyToken() {
    require(
      msg.sender == address(token),
      "MetaheroLPM#1" // msg.sender is not the token
    );

    _;
  }

  // events

  /**
   * @dev Emitted when tokens from the liquidity pool are burned
   * @param amount burnt amount
   */
  event LPBurnt(
    uint256 amount
  );

  /**
   * @dev Internal constructor
   */
  constructor ()
    internal
    Lockable()
    Owned()
    Initializable()
  {
    //
  }

  // external functions

  /**
   * @notice Syncs liquidity pool
   */
  function syncLP()
    external
    onlyToken
    lock
  {
    _syncLP();
  }

  /**
   * @notice Burns tokens from the liquidity pool
   * @param amount tokens amount
   */
  function burnLP(
    uint256 amount
  )
    external
    onlyOwner
    lockOrThrowError
  {
    require(
      amount != 0,
      "MetaheroLPM#2" // amount is zero
    );

    _burnLP(amount);

    emit LPBurnt(
      amount
    );
  }

  // external functions (views)

  function canSyncLP(
    address sender,
    address recipient
  )
    external
    view
    virtual
    returns (
      bool shouldSyncLPBefore,
      bool shouldSyncLPAfter
    );

  // internal functions

  function _initialize(
    address token_
  )
    internal
  {
    require(
      token_ != address(0),
      "MetaheroLPM#3" // token is the zero address
    );

    token = MetaheroToken(token_);
  }

  function _syncLP()
    internal
    virtual;

  function _burnLP(
    uint256 amount
  )
    internal
    virtual;
}

File 7 of 17 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

/**
 * @title ERC20 token interface
 *
 * @notice See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
 */
interface IERC20 {
  // events

  event Approval(
    address indexed owner,
    address indexed spender,
    uint256 value
  );

  event Transfer(
    address indexed from,
    address indexed to,
    uint256 value
  );

  // external functions

  function approve(
    address spender,
    uint256 value
  )
    external
    returns (bool);

  function transfer(
    address to,
    uint256 value
  )
    external
    returns (bool);

  function transferFrom(
    address from,
    address to,
    uint256 value
  )
    external
    returns (bool);

  // external functions (views)

  function totalSupply()
    external
    view
    returns (uint256);

  function balanceOf(
    address owner
  )
    external
    view
    returns (uint256);

  function allowance(
    address owner,
    address spender
  )
    external
    view
    returns (uint256);

  // external functions (pure)

  function name()
    external
    pure
    returns (string memory);

  function symbol()
    external
    pure
    returns (string memory);

  function decimals()
    external
    pure
    returns (uint8);
}

File 8 of 17 : IUniswapV2Router01.sol
// SPDX-License-Identifier: GPL-3.0
/* solhint-disable func-name-mixedcase */
pragma solidity ^0.6.12;

/**
 * @title Uniswap V2 router01 interface
 *
 * @notice Based on https://github.com/Uniswap/uniswap-v2-periphery/blob/dda62473e2da448bc9cb8f4514dadda4aeede5f4/contracts/interfaces/IUniswapV2Router01.sol
 */
interface IUniswapV2Router01 {
  // external functions

  function addLiquidityETH(
    address token,
    uint256 amountTokenDesired,
    uint256 amountTokenMin,
    uint256 amountETHMin,
    address to,
    uint256 deadline
  )
    external
    payable
    returns (uint256, uint256, uint256);

  function swapExactETHForTokens(
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external
    payable
    returns (uint256[] memory);

  function addLiquidity(
    address tokenA,
    address tokenB,
    uint256 amountADesired,
    uint256 amountBDesired,
    uint256 amountAMin,
    uint256 amountBMin,
    address to,
    uint256 deadline
  )
    external
    returns (uint256, uint256, uint256);

  function removeLiquidity(
    address tokenA,
    address tokenB,
    uint256 liquidity,
    uint256 amountAMin,
    uint256 amountBMin,
    address to,
    uint256 deadline
  )
    external
    returns (uint256, uint256);

  function removeLiquidityETH(
    address token,
    uint256 liquidity,
    uint256 amountTokenMin,
    uint256 amountETHMin,
    address to,
    uint256 deadline
  )
    external
    returns (uint256, uint256);

  function removeLiquidityWithPermit(
    address tokenA,
    address tokenB,
    uint256 liquidity,
    uint256 amountAMin,
    uint256 amountBMin,
    address to,
    uint256 deadline,
    bool approveMax,
    uint8 v,
    bytes32 r,
    bytes32 s
  )
    external
    returns (uint256, uint256);

  function removeLiquidityETHWithPermit(
    address token,
    uint256 liquidity,
    uint256 amountTokenMin,
    uint256 amountETHMin,
    address to,
    uint256 deadline,
    bool approveMax,
    uint8 v,
    bytes32 r,
    bytes32 s
  )
    external
    returns (uint256, uint256);

  function swapExactTokensForTokens(
    uint256 amountIn,
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external
    returns (uint256[] memory);

  function swapTokensForExactTokens(
    uint256 amountOut,
    uint256 amountInMax,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external
    returns (uint256[] memory);

  function swapTokensForExactETH(
    uint256 amountOut,
    uint256 amountInMax,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external
    returns (uint256[] memory);

  function swapExactTokensForETH(
    uint256 amountIn,
    uint256 amountOutMin,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external
    returns (uint256[] memory);

  function swapETHForExactTokens(
    uint256 amountOut,
    address[] calldata path,
    address to,
    uint256 deadline
  )
    external
    payable
    returns (uint256[] memory);

  // external functions (views)

  function getAmountsOut(
    uint256 amountIn,
    address[] calldata path
  )
    external
    view
    returns (uint256[] memory);

  function getAmountsIn(
    uint256 amountOut,
    address[] calldata path
  )
    external
    view
    returns (uint256[] memory);

  // external functions (pure)

  function quote(
    uint256 amountA,
    uint256 reserveA,
    uint256 reserveB
  )
    external
    pure
    returns (uint256);

  function getAmountOut(
    uint256 amountIn,
    uint256 reserveIn,
    uint256 reserveOut
  )
    external
    pure
    returns (uint256);

  function getAmountIn(
    uint256 amountOut,
    uint256 reserveIn,
    uint256 reserveOut
  )
    external
    pure
    returns (uint256);

  function factory()
    external
    pure
    returns (address);

  function WETH()
    external
    pure
    returns (address);
}

File 9 of 17 : Lockable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

/**
 * @title Lockable
 *
 * @author Stanisław Głogowski <[email protected]>
 */
contract Lockable {
  /**
   * @return true when contract is locked
   */
  bool public locked;

  // modifiers


  /**
   * @dev Calls only when contract is unlocked
   */
  modifier lock() {
    if (!locked) {
      locked = true;

      _;

      locked = false;
    }
  }

  /**
   * @dev Throws if contract is locked
   */
  modifier lockOrThrowError() {
    require(
      !locked,
      "Lockable#1" // contract is locked
    );

    locked = true;

    _;

    locked = false;
  }

  /**
   * @dev Internal constructor
   */
  constructor()
    internal
  {
    //
  }
}

File 10 of 17 : Owned.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

/**
 * @title Owned
 *
 * @author Stanisław Głogowski <[email protected]>
 */
contract Owned {
  /**
   * @return owner address
   */
  address public owner;

  // modifiers

  /**
   * @dev Throws if msg.sender is not the owner
   */
  modifier onlyOwner() {
    require(
      msg.sender == owner,
      "Owned#1" // msg.sender is not the owner
    );

    _;
  }

  // events

  /**
   * @dev Emitted when the owner is updated
   * @param owner new owner address
   */
  event OwnerUpdated(
    address owner
  );

  /**
   * @dev Internal constructor
   */
  constructor()
    internal
  {
    owner = msg.sender;
  }

  // external functions

  /**
   * @notice Sets a new owner
   * @param owner_ owner address
   */
  function setOwner(
    address owner_
  )
    external
    onlyOwner
  {
    _setOwner(owner_);
  }

  // internal functions

  function _setOwner(
    address owner_
  )
    internal
  {
    require(
      owner_ != address(0),
      "Owned#2" // owner is the zero address
    );

    require(
      owner_ != owner,
      "Owned#3" // does not update the owner
    );

    owner = owner_;

    emit OwnerUpdated(
      owner_
    );
  }
}

File 11 of 17 : Initializable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

/**
 * @title Initializable
 *
 * @author Stanisław Głogowski <[email protected]>
 */
contract Initializable {
  address private initializer;

  // modifiers

  /**
   * @dev Throws if msg.sender is not the initializer
   */
  modifier onlyInitializer() {
    require(
      initializer != address(0),
      "Initializable#1" // already initialized
    );

    require(
      msg.sender == initializer,
      "Initializable#2" // msg.sender is not the initializer
    );

    /// @dev removes initializer
    initializer = address(0);

    _;
  }

  /**
   * @dev Internal constructor
   */
  constructor()
    internal
  {
    initializer = msg.sender;
  }

  // external functions (views)

  /**
   * @notice Checks if contract is initialized
   * @return true when contract is initialized
   */
  function initialized()
    external
    view
    returns (bool)
  {
    return initializer == address(0);
  }
}

File 12 of 17 : SafeMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

/**
 * @title Safe math library
 *
 * @notice Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/5fe8f4e93bd1d4f5cc9a6899d7f24f5ffe4c14aa/contracts/math/SafeMath.sol
 */
library SafeMathLib {
  // internal functions (pure)

  /**
   * @notice Calcs a + b
   */
  function add(
    uint256 a,
    uint256 b
  )
    internal
    pure
    returns (uint256)
  {
    uint256 c = a + b;

    require(
      c >= a,
      "SafeMathLib#1"
    );

    return c;
  }

  /**
   * @notice Calcs a - b
   */
  function sub(
    uint256 a,
    uint256 b
  )
    internal
    pure
    returns (uint256)
  {
    require(
      b <= a,
      "SafeMathLib#2"
    );

    return a - b;
  }

  /**
   * @notice Calcs a x b
   */
  function mul(
    uint256 a,
    uint256 b
  )
    internal
    pure
    returns (uint256 result)
  {
    if (a != 0 && b != 0) {
      result = a * b;

      require(
        result / a == b,
        "SafeMathLib#3"
      );
    }

    return result;
  }

  /**
   * @notice Calcs a / b
   */
  function div(
    uint256 a,
    uint256 b
  )
    internal
    pure
    returns (uint256)
  {
    require(
      b != 0,
      "SafeMathLib#4"
    );

    return a / b;
  }
}

File 13 of 17 : MetaheroToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

import "./core/access/Controlled.sol";
import "./core/access/Owned.sol";
import "./core/erc20/ERC20.sol";
import "./core/lifecycle/Initializable.sol";
import "./core/math/MathLib.sol";
import "./core/math/SafeMathLib.sol";
import "./IMetaheroDAO.sol";
import "./MetaheroLPM.sol";


/**
 * @title Metahero token
 *
 * @author Stanisław Głogowski <[email protected]>
 */
contract MetaheroToken is Controlled, Owned, ERC20, Initializable {
  using MathLib for uint256;
  using SafeMathLib for uint256;

  struct Fees {
    uint256 sender; // percent from sender
    uint256 recipient; // percent from recipient
  }

  struct Settings {
    Fees burnFees; // fee taken and burned
    Fees lpFees; // fee taken and added to the liquidity pool manager
    Fees rewardsFees; // fee taken and added to rewards
    uint256 minTotalSupply; // min amount of tokens total supply
  }

  struct Summary {
    uint256 totalExcluded; // total held by excluded accounts
    uint256 totalHolding; // total held by holder accounts
    uint256 totalRewards; // total rewards
    uint256 totalSupply; // total supply
  }

  struct ExcludedAccount {
    bool exists; // true if exists
    bool excludeSenderFromFee; // removes the fee from all sender accounts on incoming transfers
    bool excludeRecipientFromFee; // removes the fee from all recipient accounts on outgoing transfers
  }

  // globals

  uint256 private constant MAX_FEE = 30; // max sum of all fees - 30%

  // metadata

  string private constant TOKEN_NAME = "Metahero";
  string private constant TOKEN_SYMBOL = "HERO";
  uint8 private constant TOKEN_DECIMALS = 18; // 0.000000000000000000

  /**
   * @return dao address
   */
  IMetaheroDAO public dao;

  /**
   * @return liquidity pool manager address
   */
  MetaheroLPM public lpm;

  /**
   * @return settings object
   */
  Settings public settings;

  /**
   * @return summary object
   */
  Summary public summary;

  /**
   * @return return true when presale is finished
   */
  bool public presaleFinished;

  mapping (address => uint256) private accountBalances;
  mapping (address => mapping (address => uint256)) private accountAllowances;
  mapping (address => ExcludedAccount) private excludedAccounts;

  // events

  /**
   * @dev Emitted when the contract is initialized
   * @param burnFees burn fees
   * @param lpFees liquidity pool fees
   * @param rewardsFees rewards fees
   * @param minTotalSupply min total supply
   * @param lpm liquidity pool manager address
   * @param controller controller address
   */
  event Initialized(
    Fees burnFees,
    Fees lpFees,
    Fees rewardsFees,
    uint256 minTotalSupply,
    address lpm,
    address controller
  );

  /**
   * @dev Emitted when the dao is updated
   * @param dao dao address
   */
  event DAOUpdated(
    address dao
  );

  /**
   * @dev Emitted when fees are updated
   * @param burnFees burn fees
   * @param lpFees liquidity pool fees
   * @param rewardsFees rewards fees
   */
  event FeesUpdated(
    Fees burnFees,
    Fees lpFees,
    Fees rewardsFees
  );

  /**
   * @dev Emitted when the presale is finished
   */
  event PresaleFinished();

  /**
   * @dev Emitted when account is excluded
   * @param account account address
   * @param excludeSenderFromFee exclude sender from fee
   * @param excludeRecipientFromFee exclude recipient from fee
   */
  event AccountExcluded(
    address indexed account,
    bool excludeSenderFromFee,
    bool excludeRecipientFromFee
  );

  /**
   * @dev Emitted when total rewards amount is updated
   * @param totalRewards total rewards amount
   */
  event TotalRewardsUpdated(
    uint256 totalRewards
  );

  // modifiers

  /**
   * @dev Throws if msg.sender is not the dao
   */
  modifier onlyDAO() {
    require(
      msg.sender == address(dao),
      "MetaheroToken#1" // msg.sender is not the dao
    );

    _;
  }

  /**
   * @dev Throws if msg.sender is not the excluded account
   */
  modifier onlyExcludedAccount() {
    require(
      excludedAccounts[msg.sender].exists,
      "MetaheroToken#2" // msg.sender is not the excluded account
    );

    _;
  }

  /**
   * @dev Public constructor
   */
  constructor ()
    public
    Controlled()
    Owned()
    ERC20(TOKEN_NAME, TOKEN_SYMBOL, TOKEN_DECIMALS) // sets metadata
    Initializable()
  {
    //
  }

  // external functions

  /**
   * @dev Initializes the contract
   * @param burnFees burn fees
   * @param lpFees liquidity pool fees
   * @param rewardsFees rewards fees
   * @param minTotalSupply min total supply
   * @param lpm_ liquidity pool manager address
   * @param controller_ controller address
   * @param totalSupply_ total supply
   */
  function initialize(
    Fees memory burnFees,
    Fees memory lpFees,
    Fees memory rewardsFees,
    uint256 minTotalSupply,
    address payable lpm_,
    address controller_,
    uint256 totalSupply_,
    address[] calldata excludedAccounts_
  )
    external
    onlyInitializer
  {
    _verifyFees(burnFees, lpFees, rewardsFees);

    settings.burnFees = burnFees;
    settings.lpFees = lpFees;
    settings.rewardsFees = rewardsFees;
    settings.minTotalSupply = minTotalSupply;

    if (
      lpFees.sender != 0 ||
      lpFees.recipient != 0
    ) {
      require(
        lpm_ != address(0),
        "MetaheroToken#3" // lpm is the zero address
      );

      lpm = MetaheroLPM(lpm_);
    }

    _initializeController(controller_);

    emit Initialized(
      burnFees,
      lpFees,
      rewardsFees,
      minTotalSupply,
      lpm_,
      controller_
    );

    // excludes owner account
    _excludeAccount(msg.sender, true, true);

    if (totalSupply_ != 0) {
      _mint(
        msg.sender,
        totalSupply_
      );
    }

    // adds predefined excluded accounts
    uint256 excludedAccountsLen = excludedAccounts_.length;

    for (uint256 index; index < excludedAccountsLen; index++) {
      _excludeAccount(excludedAccounts_[index], false, false);
    }
  }

  /**
   * @dev Sets the dao
   * @param dao_ dao address
   */
  function setDAO(
    address dao_
  )
    external
    onlyOwner
  {
    require(
      dao_ != address(0),
      "MetaheroToken#4" // lpm is the zero address
    );

    dao = IMetaheroDAO(dao_);

    emit DAOUpdated(
      dao_
    );

    // makes a dao an owner
    _setOwner(dao_);
  }

  /**
   * @dev Updates fees
   * @param burnFees burn fees
   * @param lpFees liquidity pool fees
   * @param rewardsFees rewards fees
   */
  function updateFees(
    Fees memory burnFees,
    Fees memory lpFees,
    Fees memory rewardsFees
  )
    external
    onlyDAO // only for dao
  {
    _verifyFees(burnFees, lpFees, rewardsFees);

    settings.burnFees = burnFees;
    settings.lpFees = lpFees;
    settings.rewardsFees = rewardsFees;

    emit FeesUpdated(
      burnFees,
      lpFees,
      rewardsFees
    );
  }

  /**
   * @dev Set the presale as finished
   */
  function setPresaleAsFinished()
    external
    onlyOwner
  {
    require(
      !presaleFinished,
      "MetaheroToken#5" // the presale is already finished
    );

    presaleFinished = true;

    emit PresaleFinished();
  }

  /**
   * @dev Excludes account
   * @param account account address
   * @param excludeSenderFromFee exclude sender from fee
   * @param excludeRecipientFromFee exclude recipient from fee
   */
  function excludeAccount(
    address account,
    bool excludeSenderFromFee,
    bool excludeRecipientFromFee
  )
    external
    onlyOwner
  {
    _excludeAccount(
      account,
      excludeSenderFromFee,
      excludeRecipientFromFee
    );
  }

  /**
   * @dev Approve spending limit
   * @param spender spender address
   * @param amount spending limit
   */
  function approve(
    address spender,
    uint256 amount
  )
    external
    override
    returns (bool)
  {
    _approve(
      msg.sender,
      spender,
      amount
    );

    return true;
  }

  /**
   * @dev Mints tokens to recipient
   * @param recipient recipient address
   * @param amount tokens amount
   */
  function mintTo(
    address recipient,
    uint256 amount
  )
    external
    onlyController
  {
    _mint(
      recipient,
      amount
    );
  }

  /**
   * @dev Burns tokens from msg.sender
   * @param amount tokens amount
   */
  function burn(
    uint256 amount
  )
    external
    onlyExcludedAccount
  {
    _burn(
      msg.sender,
      amount
    );
  }

  /**
   * @dev Burns tokens from sender
   * @param sender sender address
   * @param amount tokens amount
   */
  function burnFrom(
    address sender,
    uint256 amount
  )
    external
    onlyController
  {
    _burn(
      sender,
      amount
    );
  }

  /**
   * @dev Transfers tokens to recipient
   * @param recipient recipient address
   * @param amount tokens amount
   */
  function transfer(
    address recipient,
    uint256 amount
  )
    external
    override
    returns (bool)
  {
    _transfer(
      msg.sender,
      recipient,
      amount
    );

    return true;
  }

  /**
   * @dev Transfers tokens from sender to recipient
   * @param sender sender address
   * @param recipient recipient address
   * @param amount tokens amount
   */
  function transferFrom(
    address sender,
    address recipient,
    uint256 amount
  )
    external
    override
    returns (bool)
  {
    _transfer(
      sender,
      recipient,
      amount
    );

    uint256 allowance = accountAllowances[sender][msg.sender];

    require(
      allowance >= amount,
      "MetaheroToken#6"  // amount exceeds allowance
    );

    _approve( // update allowance
      sender,
      msg.sender,
      allowance.sub(amount)
    );

    return true;
  }

  // external functions (views)

  /**
   * @dev Gets excluded account
   * @param account account address
   */
  function getExcludedAccount(
    address account
  )
    external
    view
    returns (
      bool exists,
      bool excludeSenderFromFee,
      bool excludeRecipientFromFee
    )
  {
    return (
      excludedAccounts[account].exists,
      excludedAccounts[account].excludeSenderFromFee,
      excludedAccounts[account].excludeRecipientFromFee
    );
  }

  /**
   * @dev Gets total supply
   * @return total supply
   */
  function totalSupply()
    external
    view
    override
    returns (uint256)
  {
    return summary.totalSupply;
  }

  /**
   * @dev Gets allowance
   * @param owner owner address
   * @param spender spender address
   * @return allowance
   */
  function allowance(
    address owner,
    address spender
  )
    external
    view
    override
    returns (uint256)
  {
    return accountAllowances[owner][spender];
  }

  /**
   * @dev Gets balance of
   * @param account account address
   * @return result account balance
   */
  function balanceOf(
    address account
  )
    external
    view
    override
    returns (uint256 result)
  {
    result = accountBalances[account].add(
      _calcRewards(account)
    );

    return result;
  }

  /**
   * @dev Gets balance summary
   * @param account account address
   */
  function getBalanceSummary(
    address account
  )
    external
    view
    returns (
      uint256 totalBalance,
      uint256 holdingBalance,
      uint256 totalRewards
    )
  {
    holdingBalance = accountBalances[account];
    totalRewards = _calcRewards(account);
    totalBalance = holdingBalance.add(totalRewards);

    return (totalBalance, holdingBalance, totalRewards);
  }

  // private functions

  function _excludeAccount(
    address account,
    bool excludeSenderFromFee,
    bool excludeRecipientFromFee
  )
    private
  {
    require(
      account != address(0),
      "MetaheroToken#7" // account is the zero address
    );

    // if already excluded
    if (excludedAccounts[account].exists) {
      require(
        excludedAccounts[account].excludeSenderFromFee != excludeSenderFromFee ||
        excludedAccounts[account].excludeRecipientFromFee != excludeRecipientFromFee,
        "MetaheroToken#8" // does not update exclude account
      );

      excludedAccounts[account].excludeSenderFromFee = excludeSenderFromFee;
      excludedAccounts[account].excludeRecipientFromFee = excludeRecipientFromFee;
    } else {
      require(
        accountBalances[account] == 0,
        "MetaheroToken#9" // can not exclude holder account
      );

      excludedAccounts[account].exists = true;
      excludedAccounts[account].excludeSenderFromFee = excludeSenderFromFee;
      excludedAccounts[account].excludeRecipientFromFee = excludeRecipientFromFee;
    }

    emit AccountExcluded(
      account,
      excludeSenderFromFee,
      excludeRecipientFromFee
    );
  }

  function _approve(
    address owner,
    address spender,
    uint256 amount
  )
    private
  {
    require(
      spender != address(0),
      "MetaheroToken#11" // spender is the zero address
    );

    accountAllowances[owner][spender] = amount;

    emit Approval(
      owner,
      spender,
      amount
    );
  }

  function _mint(
    address recipient,
    uint256 amount
  )
    private
  {
    require(
      recipient != address(0),
      "MetaheroToken#12" // recipient is the zero address
    );

    require(
      amount != 0,
      "MetaheroToken#13" // amount is zero
    );

    summary.totalSupply = summary.totalSupply.add(amount);

    // if exclude account
    if (excludedAccounts[recipient].exists) {
      summary.totalExcluded = summary.totalExcluded.add(amount);

      accountBalances[recipient] = accountBalances[recipient].add(amount);
    } else {
      _updateHoldingBalance(
        recipient,
        accountBalances[recipient].add(amount),
        summary.totalHolding.add(amount)
      );
    }

    _emitTransfer(
      address(0),
      recipient,
      amount
    );
  }

  function _burn(
    address sender,
    uint256 amount
  )
    private
  {
    require(
      sender != address(0),
      "MetaheroToken#14" // sender is the zero address
    );

    require(
      amount != 0,
      "MetaheroToken#15" // amount is zero
    );

    require(
      accountBalances[sender] >= amount,
      "MetaheroToken#16" // amount exceeds sender balance
    );

    uint256 totalSupply_ = summary.totalSupply.sub(amount);

    if (settings.minTotalSupply != 0) {
      require(
        totalSupply_ >= settings.minTotalSupply,
        "MetaheroToken#17" // new total supply exceeds min total supply
      );
    }

    summary.totalSupply = totalSupply_;

    // if exclude account
    if (excludedAccounts[sender].exists) {
      summary.totalExcluded = summary.totalExcluded.sub(amount);

      accountBalances[sender] = accountBalances[sender].sub(amount);
    } else {
      _updateHoldingBalance(
        sender,
        accountBalances[sender].sub(amount),
        summary.totalHolding.sub(amount)
      );
    }

    _emitTransfer(
      sender,
      address(0),
      amount
    );
  }

  function _transfer(
    address sender,
    address recipient,
    uint256 amount
  )
    private
  {
    require(
      sender != address(0),
      "MetaheroToken#18" // sender is the zero address
    );

    require(
      recipient != address(0),
      "MetaheroToken#19" // recipient is the zero address
    );

    if (sender == recipient) { // special transfer type
      _syncLP(); // sync only LP

      _emitTransfer(
        sender,
        recipient,
        0
      );
    } else {
      require(
        excludedAccounts[sender].exists ||
        presaleFinished,
        "MetaheroToken#20" // presale not finished yet
      );

      require(
        amount != 0,
        "MetaheroToken#21" // amount is zero
      );

      if (
        !excludedAccounts[sender].exists &&
        !excludedAccounts[recipient].exists
      ) {
        _transferBetweenHolderAccounts(
          sender,
          recipient,
          amount
        );
      } else if (
        excludedAccounts[sender].exists &&
        !excludedAccounts[recipient].exists
      ) {
        _transferFromExcludedAccount(
          sender,
          recipient,
          amount
        );
      } else if (
        !excludedAccounts[sender].exists &&
        excludedAccounts[recipient].exists
      ) {
        _transferToExcludedAccount(
          sender,
          recipient,
          amount
        );
      } else {
        _transferBetweenExcludedAccounts(
          sender,
          recipient,
          amount
        );
      }
    }
  }

  function _transferBetweenHolderAccounts(
    address sender,
    address recipient,
    uint256 amount
  )
    private
  {
    uint256 senderAmount;
    uint256 senderBurnFee;
    uint256 senderLpFee;

    uint256 recipientAmount;
    uint256 recipientBurnFee;
    uint256 recipientLpFee;

    uint256 totalFee;

    {
      uint256 totalSupply_ = summary.totalSupply;

      // calc fees for sender and recipient
      {
        uint256 senderTotalFee;
        uint256 recipientTotalFee;

        (
          senderTotalFee,
          senderBurnFee,
          senderLpFee
        ) = _calcTransferSenderFees(amount);

        (
          totalSupply_,
          senderTotalFee,
          senderBurnFee
        ) = _matchTotalSupplyWithFees(totalSupply_, senderTotalFee, senderBurnFee);

        (
          recipientTotalFee,
          recipientBurnFee,
          recipientLpFee
        ) = _calcTransferRecipientFees(amount);

        (
          totalSupply_,
          recipientTotalFee,
          recipientBurnFee
        ) = _matchTotalSupplyWithFees(totalSupply_, recipientTotalFee, recipientBurnFee);

        totalFee = senderTotalFee.add(recipientTotalFee);
        senderAmount = amount.add(senderTotalFee);
        recipientAmount = amount.sub(recipientTotalFee);
      }

      // appends total rewards
      if (summary.totalRewards != 0) {
        uint256 totalHoldingWithRewards = summary.totalHolding.add(
          summary.totalRewards
        );

        senderAmount = senderAmount.mul(summary.totalHolding).div(
          totalHoldingWithRewards
        );
        recipientAmount = recipientAmount.mul(summary.totalHolding).div(
          totalHoldingWithRewards
        );
        totalFee = totalFee.mul(summary.totalHolding).div(
          totalHoldingWithRewards
        );
      }

      require(
        accountBalances[sender] >= senderAmount,
        "MetaheroToken#22" // amount exceeds sender balance
      );

      summary.totalSupply = totalSupply_;

      // reduce local vars
      senderAmount = accountBalances[sender].sub(senderAmount);
      recipientAmount = accountBalances[recipient].add(recipientAmount);

      _updateHoldingBalances(
        sender,
        senderAmount,
        recipient,
        recipientAmount,
        summary.totalHolding.sub(totalFee)
      );

      _increaseTotalLP(senderLpFee.add(recipientLpFee));
    }

    // emits events

    {
      _emitTransfer(
        sender,
        recipient,
        amount
      );

      _emitTransfer(
        sender,
        address(0),
        senderBurnFee
      );

      _emitTransfer(
        sender,
        address(lpm),
        senderLpFee
      );

      _emitTransfer(
        recipient,
        address(0),
        recipientBurnFee
      );

      _emitTransfer(
        recipient,
        address(lpm),
        recipientLpFee
      );

      _updateTotalRewards();

      _syncLP();
    }
  }

  function _transferFromExcludedAccount(
    address sender,
    address recipient,
    uint256 amount
  )
    private
  {
    require(
      accountBalances[sender] >= amount,
      "MetaheroToken#23" // amount exceeds sender balance
    );

    (
      bool shouldSyncLPBefore,
      bool shouldSyncLPAfter
    ) = _canSyncLP(
      sender,
      address(0)
    );

    if (shouldSyncLPBefore) {
      lpm.syncLP();
    }

    uint256 recipientTotalFee;
    uint256 recipientBurnFee;
    uint256 recipientLPFee;

    uint256 totalSupply_ = summary.totalSupply;

    // when sender does not remove the fee from the recipient
    if (!excludedAccounts[sender].excludeRecipientFromFee) {
      (
        recipientTotalFee,
        recipientBurnFee,
        recipientLPFee
      ) = _calcTransferRecipientFees(amount);

      (
        totalSupply_,
        recipientTotalFee,
        recipientBurnFee
      ) = _matchTotalSupplyWithFees(totalSupply_, recipientTotalFee, recipientBurnFee);
    }

    uint256 recipientAmount = amount.sub(recipientTotalFee);

    summary.totalSupply = totalSupply_;
    summary.totalExcluded = summary.totalExcluded.sub(amount);

    accountBalances[sender] = accountBalances[sender].sub(amount);

    _updateHoldingBalance(
      recipient,
      accountBalances[recipient].add(recipientAmount),
      summary.totalHolding.add(recipientAmount)
    );

    _increaseTotalLP(recipientLPFee);

    // emits events

    _emitTransfer(
      sender,
      recipient,
      amount
    );

    _emitTransfer(
      recipient,
      address(0),
      recipientBurnFee
    );

    _emitTransfer(
      recipient,
      address(lpm),
      recipientLPFee
    );

    _updateTotalRewards();

    if (shouldSyncLPAfter) {
      lpm.syncLP();
    }
  }

  function _transferToExcludedAccount(
    address sender,
    address recipient,
    uint256 amount
  )
    private
  {
    (
      bool shouldSyncLPBefore,
      bool shouldSyncLPAfter
    ) = _canSyncLP(
      address(0),
      recipient
    );

    if (shouldSyncLPBefore) {
      lpm.syncLP();
    }

    uint256 senderTotalFee;
    uint256 senderBurnFee;
    uint256 senderLpFee;

    uint256 totalSupply_ = summary.totalSupply;

    // when recipient does not remove the fee from the sender
    if (!excludedAccounts[recipient].excludeSenderFromFee) {
      (
        senderTotalFee,
        senderBurnFee,
        senderLpFee
      ) = _calcTransferSenderFees(amount);

      (
        totalSupply_,
        senderTotalFee,
        senderBurnFee
      ) = _matchTotalSupplyWithFees(totalSupply_, senderTotalFee, senderBurnFee);
    }

    uint256 senderAmount = amount.add(senderTotalFee);

    // append total rewards
    if (summary.totalRewards != 0) {
      uint256 totalHoldingWithRewards = summary.totalHolding.add(
        summary.totalRewards
      );

      senderAmount = senderAmount.mul(summary.totalHolding).div(
        totalHoldingWithRewards
      );
    }

    require(
      accountBalances[sender] >= senderAmount,
      "MetaheroToken#24" // amount exceeds sender balance
    );

    summary.totalSupply = totalSupply_;
    summary.totalExcluded = summary.totalExcluded.add(amount);

    accountBalances[recipient] = accountBalances[recipient].add(amount);

    _updateHoldingBalance(
      sender,
      accountBalances[sender].sub(senderAmount),
      summary.totalHolding.sub(senderAmount)
    );

    _increaseTotalLP(senderLpFee);

    // emits events

    _emitTransfer(
      sender,
      recipient,
      amount
    );

    _emitTransfer(
      sender,
      address(0),
      senderBurnFee
    );

    _emitTransfer(
      sender,
      address(lpm),
      senderLpFee
    );

    _updateTotalRewards();

    if (shouldSyncLPAfter) {
      lpm.syncLP();
    }
  }

  function _transferBetweenExcludedAccounts(
    address sender,
    address recipient,
    uint256 amount
  )
    private
  {
    require(
      accountBalances[sender] >= amount,
      "MetaheroToken#25" // amount exceeds sender balance
    );

    (
      bool shouldSyncLPBefore,
      bool shouldSyncLPAfter
    ) = _canSyncLP(
      address(0),
      recipient
    );

    if (shouldSyncLPBefore) {
      lpm.syncLP();
    }

    accountBalances[sender] = accountBalances[sender].sub(amount);
    accountBalances[recipient] = accountBalances[recipient].add(amount);

    _emitTransfer(
      sender,
      recipient,
      amount
    );

    if (shouldSyncLPAfter) {
      lpm.syncLP();
    }
  }

  function _updateHoldingBalance(
    address holder,
    uint256 holderBalance,
    uint256 totalHolding
  )
    private
  {
    accountBalances[holder] = holderBalance;
    summary.totalHolding = totalHolding;

    if (address(dao) != address(0)) { // if dao is not the zero address
      dao.syncMember(
        holder,
        holderBalance,
        totalHolding
      );
    }
  }

  function _updateHoldingBalances(
    address holderA,
    uint256 holderABalance,
    address holderB,
    uint256 holderBBalance,
    uint256 totalHolding
  )
    private
  {
    accountBalances[holderA] = holderABalance;
    accountBalances[holderB] = holderBBalance;
    summary.totalHolding = totalHolding;

    if (address(dao) != address(0)) { // if dao is not the zero address
      dao.syncMembers(
        holderA,
        holderABalance,
        holderB,
        holderBBalance,
        totalHolding
      );
    }
  }

  function _emitTransfer(
    address sender,
    address recipient,
    uint256 amount
  )
    private
  {
    if (amount != 0) { // when amount is not zero
      emit Transfer(
        sender,
        recipient,
        amount
      );
    }
  }

  function _increaseTotalLP(
    uint256 amount
  )
    private
  {
    if (amount != 0) { // when amount is not zero
      accountBalances[address(lpm)] = accountBalances[address(lpm)].add(amount);

      summary.totalExcluded = summary.totalExcluded.add(amount);
    }
  }

  function _syncLP()
    private
  {
    if (address(lpm) != address(0)) { // if lpm is not the zero address
      lpm.syncLP();
    }
  }

  function _updateTotalRewards()
    private
  {
    // totalRewards = totalSupply - totalExcluded - totalHolding
    uint256 totalRewards = summary.totalSupply
    .sub(summary.totalExcluded)
    .sub(summary.totalHolding);

    if (totalRewards != summary.totalRewards) {
      summary.totalRewards = totalRewards;

      emit TotalRewardsUpdated(
        totalRewards
      );
    }
  }

  // private functions (views)

  function _matchTotalSupplyWithFees(
    uint256 totalSupply_,
    uint256 totalFee,
    uint256 burnFee
  )
    private
    view
    returns (uint256, uint256, uint256)
  {
    if (burnFee != 0) {
      uint256 newTotalSupply = totalSupply_.sub(burnFee);

      if (newTotalSupply >= settings.minTotalSupply) {
        totalSupply_ = newTotalSupply;
      } else  { // turn of burn fee
        totalFee = totalFee.sub(burnFee);
        burnFee = 0;
      }
    }

    return (totalSupply_, totalFee, burnFee);
  }


  function _canSyncLP(
    address sender,
    address recipient
  )
    private
    view
    returns (
      bool shouldSyncLPBefore,
      bool shouldSyncLPAfter
    )
  {
    if (address(lpm) != address(0)) { // if lpm is not the zero address
      (shouldSyncLPBefore, shouldSyncLPAfter) = lpm.canSyncLP(
        sender,
        recipient
      );
    }

    return (shouldSyncLPBefore, shouldSyncLPAfter);
  }

  function _calcRewards(
    address account
  )
    private
    view
    returns (uint256 result)
  {
    if (
      !excludedAccounts[account].exists && // only for holders
      summary.totalRewards != 0
    ) {
      result = summary.totalRewards
        .mul(accountBalances[account])
        .div(summary.totalHolding);
    }

    return result;
  }

  function _calcTransferSenderFees(
    uint256 amount
  )
    private
    view
    returns (
      uint256 totalFee,
      uint256 burnFee,
      uint256 lpFee
    )
  {
    uint256 rewardsFee = amount.percent(settings.rewardsFees.sender);

    lpFee = amount.percent(settings.lpFees.sender);
    burnFee = amount.percent(settings.burnFees.sender);

    totalFee = lpFee.add(rewardsFee).add(burnFee);

    return (totalFee, burnFee, lpFee);
  }

  function _calcTransferRecipientFees(
    uint256 amount
  )
    private
    view
    returns (
      uint256 totalFee,
      uint256 burnFee,
      uint256 lpFee
    )
  {
    uint256 rewardsFee = amount.percent(settings.rewardsFees.recipient);

    lpFee = amount.percent(settings.lpFees.recipient);
    burnFee = amount.percent(settings.burnFees.recipient);

    totalFee = lpFee.add(rewardsFee).add(burnFee);

    return (totalFee, burnFee, lpFee);
  }

  // private functions (pure)

  function _verifyFees(
    Fees memory burnFees,
    Fees memory lpFees,
    Fees memory rewardsFees
  )
    private
    pure
  {
    uint256 totalFee = burnFees.sender.add(
      burnFees.recipient
    ).add(
      lpFees.sender.add(lpFees.recipient)
    ).add(
      rewardsFees.sender.add(rewardsFees.recipient)
    );

    require(
      totalFee <= MAX_FEE,
      "MetaheroToken#26" // the total fee is too high
    );
  }
}

File 14 of 17 : Controlled.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

/**
 * @title Controlled
 *
 * @author Stanisław Głogowski <[email protected]>
 */
contract Controlled {
  /**
   * @return controller address
   */
  address public controller;

  // modifiers

  /**
   * @dev Throws if msg.sender is not the controller
   */
  modifier onlyController() {
    require(
      msg.sender == controller,
      "Controlled#1" // msg.sender is not the controller
    );

    _;
  }

  // events

  /**
   * @dev Emitted when the controller is updated
   * @param controller new controller address
   */
  event ControllerUpdated(
    address controller
  );

  /**
   * @dev Internal constructor
   */
  constructor()
    internal
  {
    //
  }

  // internal functions

  function _initializeController(
    address controller_
  )
    internal
  {
    controller = controller_;
  }

  function _setController(
    address controller_
  )
    internal
  {
    require(
      controller_ != address(0),
      "Controlled#2" // controller is the zero address
    );

    require(
      controller_ != controller,
      "Controlled#3" // does not update the controller
    );

    controller = controller_;

    emit ControllerUpdated(
      controller_
    );
  }

  function _removeController()
    internal
  {
    require(
      controller != address(0),
      "Controlled#4" // controller is the zero address
    );

    controller = address(0);

    emit ControllerUpdated(
      address(0)
    );
  }
}

File 15 of 17 : ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

import "./IERC20.sol";


/**
 * @title ERC20 abstract token
 *
 * @author Stanisław Głogowski <[email protected]>
 */
abstract contract ERC20 is IERC20 {
  string public override name;
  string public override symbol;
  uint8 public override decimals;

  /**
   * @dev Internal constructor
   * @param name_ name
   * @param symbol_ symbol
   * @param decimals_ decimals amount
   */
  constructor (
    string memory name_,
    string memory symbol_,
    uint8 decimals_
  )
    internal
  {
    name = name_;
    symbol = symbol_;
    decimals = decimals_;
  }
}

File 16 of 17 : MathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

import "./SafeMathLib.sol";


/**
 * @title Math library
 *
 * @author Stanisław Głogowski <[email protected]>
 */
library MathLib {
  using SafeMathLib for uint256;

  // internal functions (pure)

  /**
   * @notice Calcs a x p / 100
   */
  function percent(
    uint256 a,
    uint256 p
  )
    internal
    pure
    returns (uint256 result)
  {
    if (a != 0 && p != 0) {
      result = a.mul(p).div(100);
    }

    return result;
  }
}

File 17 of 17 : IMetaheroDAO.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

/**
 * @title Metahero DAO interface
 *
 * @author Stanisław Głogowski <[email protected]>
 */
interface IMetaheroDAO {
  // external functions

  /**
   * @notice Called by a token to sync a dao member
   * @param member member address
   * @param memberWeight member weight
   * @param totalWeight all members weight
   */
  function syncMember(
    address member,
    uint256 memberWeight,
    uint256 totalWeight
  )
    external;

  /**
   * @notice Called by a token to sync a dao members
   * @param memberA member A address
   * @param memberAWeight member A weight
   * @param memberB member B address
   * @param memberBWeight member B weight
   * @param totalWeight all members weight
   */
  function syncMembers(
    address memberA,
    uint256 memberAWeight,
    address memberB,
    uint256 memberBWeight,
    uint256 totalWeight
  )
    external;
}

Settings
{
  "evmVersion": "istanbul",
  "metadata": {
    "bytecodeHash": "none",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"enableBurnLPAtValue","type":"uint256"},{"indexed":false,"internalType":"address","name":"stableCoin","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"uniswapRouter","type":"address"},{"indexed":false,"internalType":"address","name":"uniswapPair","type":"address"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LPBurnt","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"canSyncLP","outputs":[{"internalType":"bool","name":"shouldSyncLPBefore","type":"bool"},{"internalType":"bool","name":"shouldSyncLPAfter","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"enableBurnLPAtValue","type":"uint256"},{"internalType":"address","name":"stableCoin","type":"address"},{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"uniswapRouter_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"locked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settings","outputs":[{"internalType":"uint256","name":"enableBurnLPAtValue","type":"uint256"},{"internalType":"address","name":"stableCoin","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"syncLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract MetaheroToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapFactory","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapPair","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapRouter","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801561001057600080fd5b5033600060016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550612d1c806100a26000396000f3fe6080604052600436106100e15760003560e01c80638da5cb5b1161007f578063cf30901211610059578063cf309012146103f5578063d0e30db014610422578063e06174e41461042c578063fc0c546a14610474576100f1565b80638da5cb5b14610338578063c6ef206114610379578063c816841b146103b4576100f1565b806339071c9e116100bb57806339071c9e14610204578063735de9f71461021b578063754d1d541461025c5780638bdb2afa146102f7576100f1565b806313af4035146100f6578063158ef93e146101475780632070e9ea14610174576100f1565b366100f1576100ef346104b5565b005b600080fd5b34801561010257600080fd5b506101456004803603602081101561011957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506105b2565b005b34801561015357600080fd5b5061015c610681565b60405180821515815260200191505060405180910390f35b34801561018057600080fd5b506101e36004803603604081101561019757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506106d9565b60405180831515815260200182151581526020019250505060405180910390f35b34801561021057600080fd5b5061021961079d565b005b34801561022757600080fd5b506102306108b1565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561026857600080fd5b506102f56004803603608081101561027f57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108d7565b005b34801561030357600080fd5b5061030c611119565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561034457600080fd5b5061034d61113f565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561038557600080fd5b506103b26004803603602081101561039c57600080fd5b8101908080359060200190929190505050611165565b005b3480156103c057600080fd5b506103c9611397565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561040157600080fd5b5061040a6113bd565b60405180821515815260200191505060405180910390f35b61042a6113ce565b005b34801561043857600080fd5b506104416113d9565b604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390f35b34801561048057600080fd5b5061048961140b565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600081141561052c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4d6574616865726f4c504d466f72556e6973776170563223310000000000000081525060200191505060405180910390fd5b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561059657600080fd5b505af11580156105aa573d6000803e3d6000fd5b505050505050565b600060019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610675576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260078152602001807f4f776e656423310000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b61067e81611431565b50565b60008073ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b600080600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461079657600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156107905760019150610795565b600190505b5b9250929050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610860576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4d6574616865726f4c504d23310000000000000000000000000000000000000081525060200191505060405180910390fd5b60008054906101000a900460ff166108af5760016000806101000a81548160ff021916908315150217905550610894611629565b60008060006101000a81548160ff0219169083151502179055505b565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561099c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f496e697469616c697a61626c652331000000000000000000000000000000000081525060200191505060405180910390fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f496e697469616c697a61626c652332000000000000000000000000000000000081525060200191505060405180910390fd5b6000600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610aaa82611740565b60008414610ba457600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610b55576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4d6574616865726f4c504d466f72556e6973776170563223320000000000000081525060200191505060405180910390fd5b8360036000018190555082600360010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610c47576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4d6574616865726f4c504d466f72556e6973776170563223330000000000000081525060200191505060405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015610cf057600080fd5b505afa158015610d04573d6000803e3d6000fd5b505050506040513d6020811015610d1a57600080fd5b8101908080519060200190929190505050600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ad5c46486040518163ffffffff1660e01b815260040160206040518083038186803b158015610dd357600080fd5b505afa158015610de7573d6000803e3d6000fd5b505050506040513d6020811015610dfd57600080fd5b8101908080519060200190929190505050600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c9c65396600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600087803b158015610f3b57600080fd5b505af1158015610f4f573d6000803e3d6000fd5b505050506040513d6020811015610f6557600080fd5b8101908080519060200190929190505050600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1610600860146101000a81548160ff0219169083151502179055507f8116ad789877047f333ab33efd05e6dc66f5b1502332b352228bc3b255f1e53f84848484600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16604051808681526020018573ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019550505050505060405180910390a150505050565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611228576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260078152602001807f4f776e656423310000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60008054906101000a900460ff16156112a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600a8152602001807f4c6f636b61626c6523310000000000000000000000000000000000000000000081525060200191505060405180910390fd5b60016000806101000a81548160ff021916908315150217905550600081141561133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4d6574616865726f4c504d23320000000000000000000000000000000000000081525060200191505060405180910390fd5b61134381611827565b7fe3db70ba43f7940bc29634841e90cdb99fc06122f1325274d87be88eb8292c59816040518082815260200191505060405180910390a160008060006101000a81548160ff02191690831515021790555050565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900460ff1681565b6113d7346104b5565b565b60038060000154908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905082565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156114d4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260078152602001807f4f776e656423320000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b600060019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611598576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260078152602001807f4f776e656423330000000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b80600060016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b81604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156116b457600080fd5b505afa1580156116c8573d6000803e3d6000fd5b505050506040513d60208110156116de57600080fd5b810190808051906020019092919050505090506002811061173d57600061170f600283611c4b90919063ffffffff16565b905060006117268284611cd590919063ffffffff16565b905061173182611d58565b61173a81612133565b50505b50565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156117e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4d6574616865726f4c504d23330000000000000000000000000000000000000081525060200191505060405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060036000015414611a5957600061183e612582565b50905060008114156118b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4d6574616865726f4c504d466f72556e6973776170563223340000000000000081525060200191505060405180910390fd5b8082111561192e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4d6574616865726f4c504d466f72556e6973776170563223350000000000000081525060200191505060405180910390fd5b600061193982612696565b905060036000015481116119b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4d6574616865726f4c504d466f72556e6973776170563223360000000000000081525060200191505060405180910390fd5b60006119c084612696565b905060006119dc60036000015484611cd590919063ffffffff16565b905080821115611a54576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4d6574616865726f4c504d466f72556e6973776170563223370000000000000081525060200191505060405180910390fd5b505050505b611a616129d8565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611aec57600080fd5b505afa158015611b00573d6000803e3d6000fd5b505050506040513d6020811015611b1657600080fd5b8101908080519060200190929190505050905081811015611b9f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260198152602001807f4d6574616865726f4c504d466f72556e6973776170563223380000000000000081525060200191505060405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166342966c68836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015611c1457600080fd5b505af1158015611c28573d6000803e3d6000fd5b50505050611c47611c428383611cd590919063ffffffff16565b612133565b5050565b600080821415611cc3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f536166654d6174684c696223340000000000000000000000000000000000000081525060200191505060405180910390fd5b818381611ccc57fe5b04905092915050565b600082821115611d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f536166654d6174684c696223320000000000000000000000000000000000000081525060200191505060405180910390fd5b818303905092915050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015611e0d57600080fd5b505af1158015611e21573d6000803e3d6000fd5b505050506040513d6020811015611e3757600080fd5b8101908080519060200190929190505050506060600267ffffffffffffffff81118015611e6357600080fd5b50604051908082528060200260200182016040528015611e925781602001602082028036833780820191505090505b509050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681600081518110611ec557fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681600181518110611f2f57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338ed17398360008430426040518663ffffffff1660e01b815260040180868152602001858152602001806020018473ffffffffffffffffffffffffffffffffffffffff168152602001838152602001828103825285818151815260200191508051906020019060200280838360005b8381101561202d578082015181840152602081019050612012565b505050509050019650505050505050600060405180830381600087803b15801561205657600080fd5b505af192505050801561212457506040513d6000823e3d601f19601f82011682018060405250602081101561208a57600080fd5b81019080805160405193929190846401000000008211156120aa57600080fd5b838201915060208201858111156120c057600080fd5b82518660208202830111640100000000821117156120dd57600080fd5b8083526020830192505050908051906020019060200280838360005b838110156121145780820151818401526020810190506120f9565b5050505090500160405250505060015b61212d5761212f565b505b5050565b6000600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156121be57600080fd5b505afa1580156121d2573d6000803e3d6000fd5b505050506040513d60208110156121e857600080fd5b810190808051906020019092919050505090506000821415801561220d575060008114155b1561257e57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156122c757600080fd5b505af11580156122db573d6000803e3d6000fd5b505050506040513d60208110156122f157600080fd5b810190808051906020019092919050505050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156123b857600080fd5b505af11580156123cc573d6000803e3d6000fd5b505050506040513d60208110156123e257600080fd5b810190808051906020019092919050505050600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663e8e33700600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16858560008030426040518963ffffffff1660e01b8152600401808973ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1681526020018781526020018681526020018581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200198505050505050505050606060405180830381600087803b15801561252857600080fd5b505af192505050801561257057506040513d606081101561254857600080fd5b8101908080519060200190929190805190602001909291908051906020019092919050505060015b6125795761257d565b5050505b5b5050565b600080600080600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156125f057600080fd5b505afa158015612604573d6000803e3d6000fd5b505050506040513d606081101561261a57600080fd5b810190808051906020019092919080519060200190929190805190602001909291905050505091509150600860149054906101000a900460ff1661265f578082612662565b81815b816dffffffffffffffffffffffffffff169150806dffffffffffffffffffffffffffff169050809450819550505050509091565b60006060600367ffffffffffffffff811180156126b257600080fd5b506040519080825280602002602001820160405280156126e15781602001602082028036833780820191505090505b509050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160008151811061271457fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160018151811061277e57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600360010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16816002815181106127eb57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506060600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d06ca61f85846040518363ffffffff1660e01b81526004018083815260200180602001828103825283818151815260200191508051906020019060200280838360005b838110156128bf5780820151818401526020810190506128a4565b50505050905001935050505060006040518083038186803b1580156128e357600080fd5b505afa1580156128f7573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250602081101561292157600080fd5b810190808051604051939291908464010000000082111561294157600080fd5b8382019150602082018581111561295757600080fd5b825186602082028301116401000000008211171561297457600080fd5b8083526020830192505050908051906020019060200280838360005b838110156129ab578082015181840152602081019050612990565b505050509050016040525050509050806002815181106129c757fe5b602002602001015192505050919050565b6000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612a6357600080fd5b505afa158015612a77573d6000803e3d6000fd5b505050506040513d6020811015612a8d57600080fd5b8101908080519060200190929190505050905060008114612d0c57600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663095ea7b3600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612b5d57600080fd5b505af1158015612b71573d6000803e3d6000fd5b505050506040513d6020811015612b8757600080fd5b810190808051906020019092919050505050600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663baa2abde600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168460008030426040518863ffffffff1660e01b8152600401808873ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018681526020018581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019750505050505050506040805180830381600087803b158015612cc457600080fd5b505af1158015612cd8573d6000803e3d6000fd5b505050506040513d6040811015612cee57600080fd5b81019080805190602001909291908051906020019092919050505050505b5056fea164736f6c634300060c000a

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
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.