Contract 0x75783716eab35f41b53112c77576bf4fc638a837

 
Txn Hash Method
Block
From
To
Value
0xe1936c90f8f922051139657df16f7ded47109b512f5500f53632ec22c99c4beb0x6080604064090712022-04-25 5:58:56693 days 20 hrs ago0xef31d75a2f85cfdd9032158a2ceb773c84d79192 IN  Create: AaveLendingPoolAssetGuard0 ETH0.0094000102840.001
[ Download CSV Export 
View more zero value Internal Transactions in Advanced View mode
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AaveLendingPoolAssetGuard

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : AaveLendingPoolAssetGuard.sol
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "./ERC20Guard.sol";
import "../../interfaces/IERC20Extended.sol";
import "../../interfaces/guards/IAaveLendingPoolAssetGuard.sol";
import "../../interfaces/aave/IAaveProtocolDataProvider.sol";
import "../../interfaces/IHasAssetInfo.sol";
import "../../interfaces/IHasSupportedAsset.sol";
import "../../interfaces/IPoolLogic.sol";
import "../../interfaces/IHasGuardInfo.sol";
import "../../interfaces/uniswapv2/IUniswapV2Router.sol";

/// @title Aave lending pool asset guard
/// @dev Asset type = 3 : v2
/// @dev Asset type = 8 : v3
contract AaveLendingPoolAssetGuard is ERC20Guard, IAaveLendingPoolAssetGuard {
  using SafeMathUpgradeable for uint256;

  // For Aave decimal calculation
  // solhint-disable-next-line state-visibility
  uint256 constant DECIMALS_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF;
  // solhint-disable-next-line state-visibility
  uint256 constant RESERVE_DECIMALS_START_BIT_POSITION = 48;

  IAaveProtocolDataProvider public aaveProtocolDataProvider;
  address public override aaveLendingPool;

  constructor(address _aaveProtocolDataProvider, address _aaveLendingPool) {
    // solhint-disable-next-line reason-string
    require(_aaveProtocolDataProvider != address(0), "_aaveProtocolDataProvider address cannot be 0");
    // solhint-disable-next-line reason-string
    require(_aaveLendingPool != address(0), "_aaveLendingPool address cannot be 0");
    aaveProtocolDataProvider = IAaveProtocolDataProvider(_aaveProtocolDataProvider);
    aaveLendingPool = _aaveLendingPool;
  }

  /// @notice Returns the pool position of Aave lending pool
  /// @dev Returns the balance priced in ETH
  /// @param pool The pool logic address
  /// @return balance The total balance of the pool
  function getBalance(address pool, address) public view override returns (uint256 balance) {
    IHasSupportedAsset poolManagerLogicAssets = IHasSupportedAsset(IPoolLogic(pool).poolManagerLogic());
    IHasSupportedAsset.Asset[] memory supportedAssets = poolManagerLogicAssets.getSupportedAssets();

    address asset;
    uint256 decimals;
    uint256 tokenPriceInUsd;
    uint256 collateralBalance;
    uint256 debtBalance;
    uint256 totalCollateralInUsd;
    uint256 totalDebtInUsd;
    address factory = IPoolLogic(pool).factory();

    uint256 length = supportedAssets.length;
    for (uint256 i = 0; i < length; i++) {
      asset = supportedAssets[i].asset;

      // Lending/Borrowing enabled asset
      if (IHasAssetInfo(factory).getAssetType(asset) == 4) {
        (collateralBalance, debtBalance, decimals) = _calculateAaveBalance(pool, asset);

        if (collateralBalance != 0 || debtBalance != 0) {
          tokenPriceInUsd = IHasAssetInfo(factory).getAssetPrice(asset);
          totalCollateralInUsd = totalCollateralInUsd.add(tokenPriceInUsd.mul(collateralBalance).div(10**decimals));
          totalDebtInUsd = totalDebtInUsd.add(tokenPriceInUsd.mul(debtBalance).div(10**decimals));
        }
      }
    }

    balance = totalCollateralInUsd.sub(totalDebtInUsd);
  }

  /// @notice Returns decimal of the Aave lending pool asset
  /// @dev Returns decimal 18
  function getDecimals(address) external pure override returns (uint256 decimals) {
    decimals = 18;
  }

  /// @notice Creates transaction data for withdrawing tokens
  /// @dev Withdrawal processing is not applicable for this guard
  /// @return withdrawAsset and
  /// @return withdrawBalance are used to withdraw portion of asset balance to investor
  /// @return transactions is used to execute the withdrawal transaction in PoolLogic
  function withdrawProcessing(
    address pool, // pool
    address, // asset
    uint256 portion, // portion
    address to
  )
    external
    view
    virtual
    override
    returns (
      address withdrawAsset,
      uint256 withdrawBalance,
      MultiTransaction[] memory transactions
    )
  {
    (
      address[] memory borrowAssets,
      uint256[] memory borrowAmounts,
      uint256[] memory interestRateModes
    ) = _calculateBorrowAssets(pool, portion);

    if (borrowAssets.length > 0) {
      address factory = IPoolLogic(pool).factory();
      // Changing the withdraw asset to WETH here as this is the asset used in `_repayFlashloanTransactions`
      // for the remaining after flashloan replay.
      withdrawAsset = IHasGuardInfo(factory).getAddress("weth");
      // This adds a transaction that will initiate the flashloan flow from aave,
      // Aave will callback the higher level PoolLogic.executeOperation
      transactions = _prepareFlashLoan(pool, portion, borrowAssets, borrowAmounts, interestRateModes);
      return (withdrawAsset, 0, transactions);
    } else {
      transactions = _withdrawAndTransfer(pool, to, portion);
      // There is no asset to withdraw as the above executes the withdraw to the withdrawer(to)
      return (address(0), 0, transactions);
    }
  }

  /// @notice Prepare flashlan transaction data
  /// @param pool the PoolLogic address
  /// @param borrowAssets the borrowed assets list
  /// @param borrowAmounts the borrowed amount per each asset
  /// @param interestRateModes the interest rate mode per each asset
  /// @param portion the portion of assets to be withdrawn
  /// @return transactions is used to execute the withdrawal transaction in PoolLogic
  function _prepareFlashLoan(
    address pool,
    uint256 portion,
    address[] memory borrowAssets,
    uint256[] memory borrowAmounts,
    uint256[] memory interestRateModes
  ) internal view returns (MultiTransaction[] memory transactions) {
    transactions = new MultiTransaction[](1);

    transactions[0].to = aaveLendingPool;

    bytes memory params = abi.encode(interestRateModes, portion);
    uint256[] memory modes = new uint256[](borrowAssets.length);
    transactions[0].txData = abi.encodeWithSelector(
      bytes4(keccak256("flashLoan(address,address[],uint256[],uint256[],address,bytes,uint16)")),
      pool, // receiverAddress
      borrowAssets,
      borrowAmounts,
      modes,
      pool, // onBehalfOf
      params,
      196 // referralCode
    );
  }

  /// @notice Prepare withdraw/transfer transacton data
  /// @param pool the PoolLogic address
  /// @param to the recipient address
  /// @param portion the portion of assets to be withdrawn
  /// @return transactions is used to execute the withdrawal transaction in PoolLogic
  function _withdrawAndTransfer(
    address pool,
    address to,
    uint256 portion
  ) internal view returns (MultiTransaction[] memory transactions) {
    (address[] memory collateralAssets, uint256[] memory amounts) = _calculateCollateralAssets(pool, portion);
    transactions = new MultiTransaction[](collateralAssets.length * 2);

    uint256 txCount;
    for (uint256 i = 0; i < collateralAssets.length; i++) {
      transactions[txCount].to = aaveLendingPool;
      transactions[txCount].txData = abi.encodeWithSelector(
        bytes4(keccak256("withdraw(address,uint256,address)")),
        collateralAssets[i], // receiverAddress
        amounts[i],
        pool // onBehalfOf
      );
      txCount++;

      transactions[txCount].to = collateralAssets[i];
      transactions[txCount].txData = abi.encodeWithSelector(
        bytes4(keccak256("transfer(address,uint256)")),
        to, // recipient
        amounts[i]
      );
      txCount++;
    }
  }

  /// @notice Calculates AToken/DebtToken balances
  /// @param pool the PoolLogic address
  /// @param asset the asset address
  /// @return collateralBalance the AToken balance
  /// @return debtBalance the DebtToken balance
  /// @return decimals the asset decimals
  function _calculateAaveBalance(address pool, address asset)
    internal
    view
    returns (
      uint256 collateralBalance,
      uint256 debtBalance,
      uint256 decimals
    )
  {
    (address aToken, address stableDebtToken, address variableDebtToken) = aaveProtocolDataProvider
      .getReserveTokensAddresses(asset);
    if (aToken != address(0)) {
      collateralBalance = IERC20(aToken).balanceOf(pool);
      debtBalance = IERC20(stableDebtToken).balanceOf(pool).add(IERC20(variableDebtToken).balanceOf(pool));
    }

    decimals = IERC20Extended(asset).decimals();
  }

  /// @notice Calculates AToken balances
  /// @param pool the PoolLogic address
  /// @param portion the portion of assets to be withdrawn
  /// @return collateralAssets the collateral assets list
  /// @return amounts the asset balance per each collateral asset
  function _calculateCollateralAssets(address pool, uint256 portion)
    internal
    view
    returns (address[] memory collateralAssets, uint256[] memory amounts)
  {
    IHasSupportedAsset poolManagerLogicAssets = IHasSupportedAsset(IPoolLogic(pool).poolManagerLogic());
    IHasSupportedAsset.Asset[] memory supportedAssets = poolManagerLogicAssets.getSupportedAssets();

    uint256 length = supportedAssets.length;
    collateralAssets = new address[](length);
    amounts = new uint256[](length);

    address aToken;
    uint256 index;
    for (uint256 i = 0; i < length; i++) {
      (aToken, , ) = IAaveProtocolDataProvider(aaveProtocolDataProvider).getReserveTokensAddresses(
        supportedAssets[i].asset
      );

      if (aToken != address(0)) {
        amounts[index] = IERC20(aToken).balanceOf(pool);
        if (amounts[index] != 0) {
          collateralAssets[index] = supportedAssets[i].asset;
          amounts[index] = amounts[index].mul(portion).div(10**18);
          index++;
        }
      }
    }

    // Reduce length the empty items
    uint256 reduceLength = length.sub(index);
    assembly {
      mstore(collateralAssets, sub(mload(collateralAssets), reduceLength))
      mstore(amounts, sub(mload(amounts), reduceLength))
    }
  }

  /// @notice Calculates DebtToken balances
  /// @param pool the PoolLogic address
  /// @param portion the portion of assets to be withdrawn
  /// @return borrowAssets the borrow assets list
  /// @return amounts the asset balance per each borrow asset
  /// @return interestRateModes the interest rate modes per each borrow asset
  function _calculateBorrowAssets(address pool, uint256 portion)
    internal
    view
    returns (
      address[] memory borrowAssets,
      uint256[] memory amounts,
      uint256[] memory interestRateModes
    )
  {
    IHasSupportedAsset poolManagerLogicAssets = IHasSupportedAsset(IPoolLogic(pool).poolManagerLogic());
    IHasSupportedAsset.Asset[] memory supportedAssets = poolManagerLogicAssets.getSupportedAssets();
    uint256 length = supportedAssets.length;
    borrowAssets = new address[](length);
    amounts = new uint256[](length);
    interestRateModes = new uint256[](length);

    address stableDebtToken;
    address variableDebtToken;
    uint256 index;
    for (uint256 i = 0; i < length; i++) {
      // returns address(0) if it's not supported in aave
      (, stableDebtToken, variableDebtToken) = IAaveProtocolDataProvider(aaveProtocolDataProvider)
        .getReserveTokensAddresses(supportedAssets[i].asset);

      if (stableDebtToken != address(0)) {
        amounts[index] = IERC20(stableDebtToken).balanceOf(pool);
        if (amounts[index] != 0) {
          borrowAssets[index] = supportedAssets[i].asset;
          amounts[index] = amounts[index].mul(portion).div(10**18);
          interestRateModes[index] = 1;
          index++;
          continue;
        }
      }

      if (variableDebtToken != address(0)) {
        amounts[index] = IERC20(variableDebtToken).balanceOf(pool);
        if (amounts[index] != 0) {
          borrowAssets[index] = supportedAssets[i].asset;
          amounts[index] = amounts[index].mul(portion).div(10**18);
          interestRateModes[index] = 2;
          index++;
          continue;
        }
      }
    }

    // Reduce length the empty items
    uint256 reduceLength = length.sub(index);
    assembly {
      mstore(borrowAssets, sub(mload(borrowAssets), reduceLength))
      mstore(amounts, sub(mload(amounts), reduceLength))
      mstore(interestRateModes, sub(mload(interestRateModes), reduceLength))
    }
  }

  /// @notice process flash loan and return the transactions for execution
  /// @param pool the PoolLogic address
  /// @param portion the portion of assets to be withdrawn
  /// @param repayAssets Array of assets to be repaid
  /// @param repayAmounts Array of amounts to be repaid
  /// @param premiums Array of premiums to be paid for flash loan
  /// @param interestRateModes Array of interest rate modes of the debts
  /// @return transactions Array of transactions to be executed
  function flashloanProcessing(
    address pool,
    uint256 portion,
    address[] memory repayAssets,
    uint256[] memory repayAmounts,
    uint256[] memory premiums,
    uint256[] memory interestRateModes
  ) external view virtual override returns (MultiTransaction[] memory transactions) {
    address factory = IPoolLogic(pool).factory();
    address swapRouter = IHasGuardInfo(factory).getAddress("swapRouter");
    address weth = IHasGuardInfo(factory).getAddress("weth");

    // At this stage we have the flashloan.

    // Repay the debt with out flashloans
    // This will unlock our portion of the collateral
    MultiTransaction[] memory aaveRepayTransactions = _repayAaveTransactions(
      pool,
      repayAssets,
      repayAmounts,
      interestRateModes
    );
    // Withdraw our collateral from aave and swap everything to weth
    MultiTransaction[] memory aaveWithdrawTransactions = _withdrawAaveTransactions(pool, portion, swapRouter, weth);
    // Swaps weth to the flashloaned amounts and approves aave to take back funds for loan
    MultiTransaction[] memory flashloanWithdrawTransactions = _repayFlashloanTransactions(
      pool,
      swapRouter,
      weth,
      repayAssets,
      repayAmounts,
      premiums
    );

    transactions = new MultiTransaction[](
      aaveRepayTransactions.length + aaveWithdrawTransactions.length + flashloanWithdrawTransactions.length
    );

    uint256 i;
    uint256 txCount;
    for (i = 0; i < aaveRepayTransactions.length; i++) {
      transactions[txCount].to = aaveRepayTransactions[i].to;
      transactions[txCount].txData = aaveRepayTransactions[i].txData;
      txCount++;
    }
    for (i = 0; i < aaveWithdrawTransactions.length; i++) {
      transactions[txCount].to = aaveWithdrawTransactions[i].to;
      transactions[txCount].txData = aaveWithdrawTransactions[i].txData;
      txCount++;
    }
    for (i = 0; i < flashloanWithdrawTransactions.length; i++) {
      transactions[txCount].to = flashloanWithdrawTransactions[i].to;
      transactions[txCount].txData = flashloanWithdrawTransactions[i].txData;
      txCount++;
    }
  }

  /// @notice calculate and return repay Aave transactions for execution
  /// @param pool the PoolLogic address
  /// @param repayAssets Array of assets to be repaid
  /// @param repayAmounts Array of amounts to be repaid
  /// @param interestRateModes Array of interest rate modes of the debts
  /// @return transactions Array of transactions to be executed
  function _repayAaveTransactions(
    address pool,
    address[] memory repayAssets,
    uint256[] memory repayAmounts,
    uint256[] memory interestRateModes
  ) internal view returns (MultiTransaction[] memory transactions) {
    transactions = new MultiTransaction[](repayAssets.length * 2);

    uint256 txCount;
    for (uint256 i = 0; i < repayAssets.length; i++) {
      transactions[txCount].to = repayAssets[i];
      transactions[txCount].txData = abi.encodeWithSelector(
        bytes4(keccak256("approve(address,uint256)")),
        aaveLendingPool,
        repayAmounts[i]
      );
      txCount++;

      transactions[txCount].to = aaveLendingPool;
      transactions[txCount].txData = abi.encodeWithSelector(
        bytes4(keccak256("repay(address,uint256,uint256,address)")),
        repayAssets[i],
        repayAmounts[i],
        interestRateModes[i],
        pool // onBehalfOf
      );
      txCount++;
    }
  }

  // take flashloan for debt asset

  /// @notice calculate and return withdraw Aave transactions for execution
  /// @param pool the PoolLogic address
  /// @param portion the portion of assets to be withdrawn
  /// @param swapRouter the swapRouter address
  /// @param weth the weth address to swap in the path
  /// @return transactions Array of transactions to be executed
  function _withdrawAaveTransactions(
    address pool,
    uint256 portion,
    address swapRouter,
    address weth
  ) internal view returns (MultiTransaction[] memory transactions) {
    (address[] memory collateralAssets, uint256[] memory amounts) = _calculateCollateralAssets(pool, portion);

    // We have 4 transactions for each collateral asset.
    // 1. Withdraw collateral asset from aave
    // 2. Approve collateral asset for swap router
    // 3. Swap collateral asset to WETH
    // 4. Approve collateral asset for swap router (zero amount)
    uint256 length = collateralAssets.length.mul(4);
    transactions = new MultiTransaction[](length);

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

    uint256 txCount;
    for (uint256 i = 0; i < collateralAssets.length; i++) {
      transactions[txCount].to = aaveLendingPool;
      transactions[txCount].txData = abi.encodeWithSelector(
        bytes4(keccak256("withdraw(address,uint256,address)")),
        collateralAssets[i],
        amounts[i],
        pool
      );
      txCount++;

      if (collateralAssets[i] != weth) {
        transactions[txCount].to = collateralAssets[i];
        transactions[txCount].txData = abi.encodeWithSelector(
          bytes4(keccak256("approve(address,uint256)")),
          swapRouter,
          amounts[i]
        );
        txCount++;

        path[0] = collateralAssets[i];
        transactions[txCount].to = swapRouter;
        transactions[txCount].txData = abi.encodeWithSelector(
          bytes4(keccak256("swapExactTokensForTokens(uint256,uint256,address[],address,uint256)")),
          amounts[i],
          0,
          path,
          pool,
          uint256(-1)
        );
        txCount++;

        transactions[txCount].to = collateralAssets[i];
        transactions[txCount].txData = abi.encodeWithSelector(
          bytes4(keccak256("approve(address,uint256)")),
          swapRouter,
          0
        );
        txCount++;
      }
    }

    // Reduce length the empty items
    uint256 reduceLength = length.sub(txCount);
    assembly {
      mstore(transactions, sub(mload(transactions), reduceLength))
    }
  }

  /// @notice calculate and return repay flash loan transactions for execution
  /// @param pool the PoolLogic address
  /// @param swapRouter the swapRouter address
  /// @param weth the weth address to swap in the path
  /// @param repayAssets Array of assets to be repaid
  /// @param repayAmounts Array of amounts to be repaid
  /// @param premiums Array of premiums to be paid for flash loan
  /// @return transactions Array of transactions to be executed
  function _repayFlashloanTransactions(
    address pool,
    address swapRouter,
    address weth,
    address[] memory repayAssets,
    uint256[] memory repayAmounts,
    uint256[] memory premiums
  ) internal view returns (MultiTransaction[] memory transactions) {
    // 1. Approve WETH for swap router (maximum approve)
    // 2. For each repay asset -> swap WETH to repay asset
    // 3. For each repay asset -> approve repay asset for aave lending pool (for flashloan repay)
    // 4. Approve WETH for swap router (zero amount)
    uint256 length = repayAssets.length.mul(2).add(2);
    transactions = new MultiTransaction[](length);

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

    uint256 txCount;
    transactions[txCount].to = weth;
    transactions[txCount].txData = abi.encodeWithSelector(
      bytes4(keccak256("approve(address,uint256)")),
      swapRouter,
      uint256(-1)
    );
    txCount++;

    for (uint256 i = 0; i < repayAssets.length; i++) {
      uint256 amountOwing = repayAmounts[i].add(premiums[i]);

      if (repayAssets[i] != weth) {
        path[1] = repayAssets[i];
        transactions[txCount].to = swapRouter;
        transactions[txCount].txData = abi.encodeWithSelector(
          bytes4(keccak256("swapTokensForExactTokens(uint256,uint256,address[],address,uint256)")),
          amountOwing,
          uint256(-1),
          path,
          pool,
          uint256(-1)
        );
        txCount++;
      }

      transactions[txCount].to = repayAssets[i];
      transactions[txCount].txData = abi.encodeWithSelector(
        bytes4(keccak256("approve(address,uint256)")),
        aaveLendingPool,
        amountOwing
      );
      txCount++;
    }

    transactions[txCount].to = weth;
    transactions[txCount].txData = abi.encodeWithSelector(bytes4(keccak256("approve(address,uint256)")), swapRouter, 0);
    txCount++;

    // Reduce length the empty items
    uint256 reduceLength = length.sub(txCount);
    assembly {
      mstore(transactions, sub(mload(transactions), reduceLength))
    }
  }
}

File 2 of 18 : SafeMathUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.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 SafeMathUpgradeable {
    /**
     * @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 3 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.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 18 : ERC20Guard.sol
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "../../utils/TxDataUtils.sol";
import "../../interfaces/guards/IAssetGuard.sol";
import "../../interfaces/guards/IGuard.sol";
import "../../interfaces/IERC20Extended.sol"; // includes decimals()
import "../../interfaces/IPoolManagerLogic.sol";
import "../../interfaces/IHasSupportedAsset.sol";
import "../../interfaces/IHasGuardInfo.sol";
import "../../interfaces/IManaged.sol";

/// @title Generic ERC20 asset guard
/// @dev Asset type = 0
/// @dev A generic ERC20 guard asset is Not stakeable ie. no 'getWithdrawStakedTx()' function
contract ERC20Guard is TxDataUtils, IGuard, IAssetGuard {
  using SafeMathUpgradeable for uint256;

  event Approve(address fundAddress, address manager, address spender, uint256 amount, uint256 time);

  /// @notice Transaction guard for approving assets
  /// @dev Parses the manager transaction data to ensure transaction is valid
  /// @param _poolManagerLogic Pool address
  /// @param data Transaction call data attempt by manager
  /// @return txType transaction type described in PoolLogic
  /// @return isPublic if the transaction is public or private
  function txGuard(
    address _poolManagerLogic,
    address, // to
    bytes calldata data
  )
    external
    override
    returns (
      uint16 txType, // transaction type
      bool // isPublic
    )
  {
    bytes4 method = getMethod(data);

    if (method == bytes4(keccak256("approve(address,uint256)"))) {
      address spender = convert32toAddress(getInput(data, 0));
      uint256 amount = uint256(getInput(data, 1));

      IPoolManagerLogic poolManagerLogic = IPoolManagerLogic(_poolManagerLogic);

      address factory = poolManagerLogic.factory();
      address spenderGuard = IHasGuardInfo(factory).getContractGuard(spender);
      require(spenderGuard != address(0) && spenderGuard != address(this), "unsupported spender approval"); // checks that the spender is an approved address

      emit Approve(
        poolManagerLogic.poolLogic(),
        IManaged(_poolManagerLogic).manager(),
        spender,
        amount,
        block.timestamp
      );

      txType = 1; // 'Approve' type
    }

    return (txType, false);
  }

  /// @notice Creates transaction data for withdrawing tokens
  /// @dev Withdrawal processing is not applicable for this guard
  /// @return withdrawAsset and
  /// @return withdrawBalance are used to withdraw portion of asset balance to investor
  /// @return transactions is used to execute the withdrawal transaction in PoolLogic
  function withdrawProcessing(
    address pool,
    address asset,
    uint256 portion,
    address // to
  )
    external
    view
    virtual
    override
    returns (
      address withdrawAsset,
      uint256 withdrawBalance,
      MultiTransaction[] memory transactions
    )
  {
    withdrawAsset = asset;
    uint256 totalAssetBalance = getBalance(pool, asset);
    withdrawBalance = totalAssetBalance.mul(portion).div(10**18);
    return (withdrawAsset, withdrawBalance, transactions);
  }

  /// @notice Returns the balance of the managed asset
  /// @dev May include any external balance in staking contracts
  /// @return balance The asset balance of given pool
  function getBalance(address pool, address asset) public view virtual override returns (uint256 balance) {
    // The base ERC20 guard has no externally staked tokens
    balance = IERC20(asset).balanceOf(pool);
  }

  /// @notice Returns the decimal of the managed asset
  /// @param asset Address of the managed asset
  /// @return decimals The decimal of given asset
  function getDecimals(address asset) external view virtual override returns (uint256 decimals) {
    decimals = IERC20Extended(asset).decimals();
  }

  /// @notice Necessary check for remove asset
  /// @param pool Address of the pool
  /// @param asset Address of the remove asset
  function removeAssetCheck(address pool, address asset) public view virtual override {
    uint256 balance = getBalance(pool, asset);
    require(balance == 0, "cannot remove non-empty asset");
  }
}

File 5 of 18 : IERC20Extended.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

// With aditional optional views

interface IERC20Extended {
  // ERC20 Optional Views
  function name() external view returns (string memory);

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

  function decimals() external view returns (uint8);

  // Views
  function totalSupply() external view returns (uint256);

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

  function scaledBalanceOf(address user) external view returns (uint256);

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

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

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

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

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

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

File 6 of 18 : IAaveLendingPoolAssetGuard.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "./IAssetGuard.sol";

interface IAaveLendingPoolAssetGuard {
  function flashloanProcessing(
    address pool,
    uint256 portion,
    address[] memory repayAssets,
    uint256[] memory repayAmounts,
    uint256[] memory premiums,
    uint256[] memory interestRateModes
  ) external view returns (IAssetGuard.MultiTransaction[] memory transactions);

  function aaveLendingPool() external view returns (address);
}

File 7 of 18 : IAaveProtocolDataProvider.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

interface IAaveProtocolDataProvider {
  // solhint-disable-next-line func-name-mixedcase
  function ADDRESSES_PROVIDER() external view returns (address);

  function getReserveTokensAddresses(address asset)
    external
    view
    returns (
      address aTokenAddress,
      address stableDebtTokenAddress,
      address variableDebtTokenAddress
    );
}

File 8 of 18 : IHasAssetInfo.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IHasAssetInfo {
  function isValidAsset(address asset) external view returns (bool);

  function getAssetPrice(address asset) external view returns (uint256);

  function getAssetType(address asset) external view returns (uint16);

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

File 9 of 18 : IHasSupportedAsset.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

pragma experimental ABIEncoderV2;

interface IHasSupportedAsset {
  struct Asset {
    address asset;
    bool isDeposit;
  }

  function getSupportedAssets() external view returns (Asset[] memory);

  function isSupportedAsset(address asset) external view returns (bool);
}

File 10 of 18 : IPoolLogic.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IPoolLogic {
  function factory() external view returns (address);

  function poolManagerLogic() external view returns (address);

  function setPoolManagerLogic(address _poolManagerLogic) external returns (bool);

  function availableManagerFee() external view returns (uint256 fee);

  function tokenPrice() external view returns (uint256 price);

  function tokenPriceWithoutManagerFee() external view returns (uint256 price);

  function deposit(address _asset, uint256 _amount) external returns (uint256 liquidityMinted);

  function withdraw(uint256 _fundTokenAmount) external;

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

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

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

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

File 11 of 18 : IHasGuardInfo.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IHasGuardInfo {
  // Get guard
  function getContractGuard(address extContract) external view returns (address);

  // Get asset guard
  function getAssetGuard(address extContract) external view returns (address);

  // Get mapped addresses from Governance
  function getAddress(bytes32 name) external view returns (address);
}

File 12 of 18 : IUniswapV2Router.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

interface IUniswapV2Router {
  function factory() external pure returns (address);

  // solhint-disable-next-line func-name-mixedcase
  function WETH() external view returns (address);

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

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

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

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

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

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

File 13 of 18 : TxDataUtils.sol
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
import "@uniswap/v3-periphery/contracts/libraries/BytesLib.sol";

contract TxDataUtils {
  using BytesLib for bytes;
  using SafeMathUpgradeable for uint256;

  function getMethod(bytes memory data) public pure returns (bytes4) {
    return read4left(data, 0);
  }

  function getParams(bytes memory data) public pure returns (bytes memory) {
    return data.slice(4, data.length - 4);
  }

  function getInput(bytes memory data, uint8 inputNum) public pure returns (bytes32) {
    return read32(data, 32 * inputNum + 4, 32);
  }

  function getBytes(
    bytes memory data,
    uint8 inputNum,
    uint256 offset
  ) public pure returns (bytes memory) {
    require(offset < 20, "invalid offset"); // offset is in byte32 slots, not bytes
    offset = offset * 32; // convert offset to bytes
    uint256 bytesLenPos = uint256(read32(data, 32 * inputNum + 4 + offset, 32));
    uint256 bytesLen = uint256(read32(data, bytesLenPos + 4 + offset, 32));
    return data.slice(bytesLenPos + 4 + offset + 32, bytesLen);
  }

  function getArrayLast(bytes memory data, uint8 inputNum) public pure returns (bytes32) {
    bytes32 arrayPos = read32(data, 32 * inputNum + 4, 32);
    bytes32 arrayLen = read32(data, uint256(arrayPos) + 4, 32);
    require(arrayLen > 0, "input is not array");
    return read32(data, uint256(arrayPos) + 4 + (uint256(arrayLen) * 32), 32);
  }

  function getArrayLength(bytes memory data, uint8 inputNum) public pure returns (uint256) {
    bytes32 arrayPos = read32(data, 32 * inputNum + 4, 32);
    return uint256(read32(data, uint256(arrayPos) + 4, 32));
  }

  function getArrayIndex(
    bytes memory data,
    uint8 inputNum,
    uint8 arrayIndex
  ) public pure returns (bytes32) {
    bytes32 arrayPos = read32(data, 32 * inputNum + 4, 32);
    bytes32 arrayLen = read32(data, uint256(arrayPos) + 4, 32);
    require(arrayLen > 0, "input is not array");
    require(uint256(arrayLen) > arrayIndex, "invalid array position");
    return read32(data, uint256(arrayPos) + 4 + ((1 + uint256(arrayIndex)) * 32), 32);
  }

  function read4left(bytes memory data, uint256 offset) public pure returns (bytes4 o) {
    require(data.length >= offset + 4, "Reading bytes out of bounds");
    assembly {
      o := mload(add(data, add(32, offset)))
    }
  }

  function read32(
    bytes memory data,
    uint256 offset,
    uint256 length
  ) public pure returns (bytes32 o) {
    require(data.length >= offset + length, "Reading bytes out of bounds");
    assembly {
      o := mload(add(data, add(32, offset)))
      let lb := sub(32, length)
      if lb {
        o := div(o, exp(2, mul(lb, 8)))
      }
    }
  }

  function convert32toAddress(bytes32 data) public pure returns (address o) {
    return address(uint160(uint256(data)));
  }

  function sliceUint(bytes memory data, uint256 start) internal pure returns (uint256) {
    require(data.length >= start + 32, "slicing out of range");
    uint256 x;
    assembly {
      x := mload(add(data, add(0x20, start)))
    }
    return x;
  }
}

File 14 of 18 : IAssetGuard.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "../IHasSupportedAsset.sol";

interface IAssetGuard {
  struct MultiTransaction {
    address to;
    bytes txData;
  }

  function withdrawProcessing(
    address pool,
    address asset,
    uint256 withdrawPortion,
    address to
  )
    external
    view
    returns (
      address,
      uint256,
      MultiTransaction[] memory transactions
    );

  function getBalance(address pool, address asset) external view returns (uint256 balance);

  function getDecimals(address asset) external view returns (uint256 decimals);

  function removeAssetCheck(address poolLogic, address asset) external view;
}

File 15 of 18 : IGuard.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IGuard {
  event ExchangeFrom(address fundAddress, address sourceAsset, uint256 sourceAmount, address dstAsset, uint256 time);
  event ExchangeTo(address fundAddress, address sourceAsset, address dstAsset, uint256 dstAmount, uint256 time);

  function txGuard(
    address poolManagerLogic,
    address to,
    bytes calldata data
  ) external returns (uint16 txType, bool isPublic);
}

File 16 of 18 : IPoolManagerLogic.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IPoolManagerLogic {
  function poolLogic() external view returns (address);

  function isDepositAsset(address asset) external view returns (bool);

  function validateAsset(address asset) external view returns (bool);

  function assetValue(address asset) external view returns (uint256);

  function assetValue(address asset, uint256 amount) external view returns (uint256);

  function assetBalance(address asset) external view returns (uint256 balance);

  function factory() external view returns (address);

  function setPoolLogic(address fundAddress) external returns (bool);

  function totalFundValue() external view returns (uint256);

  function isMemberAllowed(address member) external view returns (bool);

  function getFee()
    external
    view
    returns (
      uint256,
      uint256,
      uint256
    );
}

File 17 of 18 : IManaged.sol
//
//        __  __    __  ________  _______    ______   ________
//       /  |/  |  /  |/        |/       \  /      \ /        |
//   ____$$ |$$ |  $$ |$$$$$$$$/ $$$$$$$  |/$$$$$$  |$$$$$$$$/
//  /    $$ |$$ |__$$ |$$ |__    $$ |  $$ |$$ | _$$/ $$ |__
// /$$$$$$$ |$$    $$ |$$    |   $$ |  $$ |$$ |/    |$$    |
// $$ |  $$ |$$$$$$$$ |$$$$$/    $$ |  $$ |$$ |$$$$ |$$$$$/
// $$ \__$$ |$$ |  $$ |$$ |_____ $$ |__$$ |$$ \__$$ |$$ |_____
// $$    $$ |$$ |  $$ |$$       |$$    $$/ $$    $$/ $$       |
//  $$$$$$$/ $$/   $$/ $$$$$$$$/ $$$$$$$/   $$$$$$/  $$$$$$$$/
//
// dHEDGE DAO - https://dhedge.org
//
// Copyright (c) 2021 dHEDGE DAO
//
// 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
//
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

interface IManaged {
  function manager() external view returns (address);

  function trader() external view returns (address);

  function managerName() external view returns (string memory);
}

File 18 of 18 : BytesLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.5.0 <0.8.0;

library BytesLib {
    function slice(
        bytes memory _bytes,
        uint256 _start,
        uint256 _length
    ) internal pure returns (bytes memory) {
        require(_length + 31 >= _length, 'slice_overflow');
        require(_start + _length >= _start, 'slice_overflow');
        require(_bytes.length >= _start + _length, 'slice_outOfBounds');

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
                case 0 {
                    // Get a location of some free memory and store it in tempBytes as
                    // Solidity does for memory variables.
                    tempBytes := mload(0x40)

                    // The first word of the slice result is potentially a partial
                    // word read from the original array. To read it, we calculate
                    // the length of that partial word and start copying that many
                    // bytes into the array. The first word we copy will start with
                    // data we don't care about, but the last `lengthmod` bytes will
                    // land at the beginning of the contents of the new array. When
                    // we're done copying, we overwrite the full first word with
                    // the actual length of the slice.
                    let lengthmod := and(_length, 31)

                    // The multiplication in the next line is necessary
                    // because when slicing multiples of 32 bytes (lengthmod == 0)
                    // the following copy loop was copying the origin's length
                    // and then ending prematurely not copying everything it should.
                    let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                    let end := add(mc, _length)

                    for {
                        // The multiplication in the next line has the same exact purpose
                        // as the one above.
                        let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                    } lt(mc, end) {
                        mc := add(mc, 0x20)
                        cc := add(cc, 0x20)
                    } {
                        mstore(mc, mload(cc))
                    }

                    mstore(tempBytes, _length)

                    //update free-memory pointer
                    //allocating the array padded to 32 bytes like the compiler does now
                    mstore(0x40, and(add(mc, 31), not(31)))
                }
                //if we want a zero-length slice let's just return a zero-length array
                default {
                    tempBytes := mload(0x40)
                    //zero out the 32 bytes slice we are about to return
                    //we need to do it because Solidity does not garbage collect
                    mstore(tempBytes, 0)

                    mstore(0x40, add(tempBytes, 0x20))
                }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_start + 20 >= _start, 'toAddress_overflow');
        require(_bytes.length >= _start + 20, 'toAddress_outOfBounds');
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) {
        require(_start + 3 >= _start, 'toUint24_overflow');
        require(_bytes.length >= _start + 3, 'toUint24_outOfBounds');
        uint24 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x3), _start))
        }

        return tempUint;
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_aaveProtocolDataProvider","type":"address"},{"internalType":"address","name":"_aaveLendingPool","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"fundAddress","type":"address"},{"indexed":false,"internalType":"address","name":"manager","type":"address"},{"indexed":false,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"Approve","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"fundAddress","type":"address"},{"indexed":false,"internalType":"address","name":"sourceAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"sourceAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"dstAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ExchangeFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"fundAddress","type":"address"},{"indexed":false,"internalType":"address","name":"sourceAsset","type":"address"},{"indexed":false,"internalType":"address","name":"dstAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"dstAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ExchangeTo","type":"event"},{"inputs":[],"name":"aaveLendingPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aaveProtocolDataProvider","outputs":[{"internalType":"contract IAaveProtocolDataProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"data","type":"bytes32"}],"name":"convert32toAddress","outputs":[{"internalType":"address","name":"o","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"portion","type":"uint256"},{"internalType":"address[]","name":"repayAssets","type":"address[]"},{"internalType":"uint256[]","name":"repayAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"premiums","type":"uint256[]"},{"internalType":"uint256[]","name":"interestRateModes","type":"uint256[]"}],"name":"flashloanProcessing","outputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"txData","type":"bytes"}],"internalType":"struct IAssetGuard.MultiTransaction[]","name":"transactions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8","name":"inputNum","type":"uint8"},{"internalType":"uint8","name":"arrayIndex","type":"uint8"}],"name":"getArrayIndex","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8","name":"inputNum","type":"uint8"}],"name":"getArrayLast","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8","name":"inputNum","type":"uint8"}],"name":"getArrayLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8","name":"inputNum","type":"uint8"},{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"getBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getDecimals","outputs":[{"internalType":"uint256","name":"decimals","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8","name":"inputNum","type":"uint8"}],"name":"getInput","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"getMethod","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"getParams","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"read32","outputs":[{"internalType":"bytes32","name":"o","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"read4left","outputs":[{"internalType":"bytes4","name":"o","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"asset","type":"address"}],"name":"removeAssetCheck","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_poolManagerLogic","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"txGuard","outputs":[{"internalType":"uint16","name":"txType","type":"uint16"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"portion","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawProcessing","outputs":[{"internalType":"address","name":"withdrawAsset","type":"address"},{"internalType":"uint256","name":"withdrawBalance","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"txData","type":"bytes"}],"internalType":"struct IAssetGuard.MultiTransaction[]","name":"transactions","type":"tuple[]"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b5060405162003cc538038062003cc58339810160408190526200003491620000de565b6001600160a01b038216620000665760405162461bcd60e51b81526004016200005d9062000159565b60405180910390fd5b6001600160a01b0381166200008f5760405162461bcd60e51b81526004016200005d9062000115565b600080546001600160a01b039384166001600160a01b03199182161790915560018054929093169116179055620001a6565b80516001600160a01b0381168114620000d957600080fd5b919050565b60008060408385031215620000f1578182fd5b620000fc83620000c1565b91506200010c60208401620000c1565b90509250929050565b60208082526024908201527f5f616176654c656e64696e67506f6f6c20616464726573732063616e6e6f74206040820152630626520360e41b606082015260800190565b6020808252602d908201527f5f6161766550726f746f636f6c4461746150726f76696465722061646472657360408201526c0732063616e6e6f74206265203609c1b606082015260800190565b613b0f80620001b66000396000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c80636f8ae202116100a2578063c3c6279f11610071578063c3c6279f14610270578063cf54aaa014610283578063d4fac45d14610296578063db896b57146102a9578063e9d337b8146102bc57610116565b80636f8ae2021461020857806382f86acc1461022a578063952bfb161461023d578063998546e31461025d57610116565b806341dc16c3116100e957806341dc16c3146101a45780635f9d4d2e146101b75780636179309d146101bf57806368901513146101e05780636d5fae54146101f357610116565b806309ff5c7d1461011b5780631053f952146101445780631eba307714610164578063293d806314610184575b600080fd5b61012e6101293660046134d7565b6102c4565b60405161013b91906138f8565b60405180910390f35b61015761015236600461351b565b610357565b60405161013b9190613916565b610177610172366004613400565b6103ef565b60405161013b919061374b565b61019761019236600461344a565b6103f6565b60405161013b9190613901565b61012e6101b2366004613572565b61045a565b610177610538565b6101d26101cd366004613185565b610547565b60405161013b9291906139bd565b6101576101ee366004613418565b6108ac565b610206610201366004613101565b6108c7565b005b61021b610216366004613211565b6108f8565b60405161013b93929190613868565b61012e6102383660046134d7565b610a4d565b61025061024b366004613263565b610a6b565b60405161013b91906138c3565b61012e61026b3660046134d7565b610e19565b61019761027e366004613418565b610e4a565b61012e6102913660046130c9565b610e57565b61012e6102a4366004613101565b610e5d565b61012e6102b736600461348c565b611184565b610177611205565b6000806102dc848460200260040160ff166020611184565b905060006102ef85600484016020611184565b905080610338576040805162461bcd60e51b8152602060048201526012602482015271696e707574206973206e6f7420617272617960701b604482015290519081900360640190fd5b61034c856020808402850160040190611184565b925050505b92915050565b60606014821061039f576040805162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081bd9999cd95d60921b604482015290519081900360640190fd5b81602002915060006103be85848660200260040160ff16016020611184565b905060006103d3868584016004016020611184565b90506103e58660248487010183611214565b9695505050505050565b805b919050565b60008160040183511015610451576040805162461bcd60e51b815260206004820152601b60248201527f52656164696e67206279746573206f7574206f6620626f756e64730000000000604482015290519081900360640190fd5b50016020015190565b600080610472858560200260040160ff166020611184565b9050600061048586600484016020611184565b9050806104ce576040805162461bcd60e51b8152602060048201526012602482015271696e707574206973206e6f7420617272617960701b604482015290519081900360640190fd5b60ff8416811161051e576040805162461bcd60e51b815260206004820152601660248201527534b73b30b634b21030b93930bc903837b9b4ba34b7b760511b604482015290519081900360640190fd5b6103e5866020600160ff8816018102850160040190611184565b6000546001600160a01b031681565b600080600061058b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4a92505050565b90506001600160e01b0319811663095ea7b360e01b141561089e5760006105ea61017287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509250610a4d915050565b9050600061063087878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610a4d915050565b60001c905060008990506000816001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b15801561067557600080fd5b505afa158015610689573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ad91906130e5565b90506000816001600160a01b0316634f8419b9866040518263ffffffff1660e01b81526004016106dd919061374b565b60206040518083038186803b1580156106f557600080fd5b505afa158015610709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072d91906130e5565b90506001600160a01b0381161580159061075057506001600160a01b0381163014155b6107755760405162461bcd60e51b815260040161076c90613986565b60405180910390fd5b7f5343b378d69227c1bc2016fd44e8104f0ffa7729f4f4f4110e349a2db0a0d0c8836001600160a01b03166339b81fd96040518163ffffffff1660e01b815260040160206040518083038186803b1580156107cf57600080fd5b505afa1580156107e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080791906130e5565b8d6001600160a01b031663481c6a756040518163ffffffff1660e01b815260040160206040518083038186803b15801561084057600080fd5b505afa158015610854573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087891906130e5565b87874260405161088c95949392919061375f565b60405180910390a16001975050505050505b506000905094509492505050565b6060610351600480845103846112149092919063ffffffff16565b60006108d38383610e5d565b905080156108f35760405162461bcd60e51b815260040161076c90613929565b505050565b6000806060600080600061090c8a89611365565b925092509250600083511115610a2b5760008a6001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b15801561095757600080fd5b505afa15801561096b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098f91906130e5565b6040516321f8a72160e01b81529091506001600160a01b038216906321f8a721906109bc90600401613976565b60206040518083038186803b1580156109d457600080fd5b505afa1580156109e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0c91906130e5565b9650610a1b8b8a8686866118be565b600096509450610a439350505050565b610a368a888a611a2a565b9350600080955095505050505b9450945094915050565b6000610a64838360200260040160ff166020611184565b9392505050565b60606000876001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015610aa857600080fd5b505afa158015610abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae091906130e5565b90506000816001600160a01b03166321f8a7216040518163ffffffff1660e01b8152600401610b0e90613960565b60206040518083038186803b158015610b2657600080fd5b505afa158015610b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5e91906130e5565b90506000826001600160a01b03166321f8a7216040518163ffffffff1660e01b8152600401610b8c90613976565b60206040518083038186803b158015610ba457600080fd5b505afa158015610bb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdc91906130e5565b90506000610bec8b8a8a89611c83565b90506000610bfc8c8c8686611ec6565b90506000610c0e8d86868e8e8e61237b565b905080518251845101016001600160401b0381118015610c2d57600080fd5b50604051908082528060200260200182016040528015610c6757816020015b610c54612f73565b815260200190600190039081610c4c5790505b5096506000805b8451821015610cf357848281518110610c8357fe5b602002602001015160000151898281518110610c9b57fe5b60209081029190910101516001600160a01b0390911690528451859083908110610cc157fe5b602002602001015160200151898281518110610cd957fe5b602090810291909101810151015260019182019101610c6e565b600091505b8351821015610d7d57838281518110610d0d57fe5b602002602001015160000151898281518110610d2557fe5b60209081029190910101516001600160a01b0390911690528351849083908110610d4b57fe5b602002602001015160200151898281518110610d6357fe5b602090810291909101810151015260019182019101610cf8565b600091505b8251821015610e0757828281518110610d9757fe5b602002602001015160000151898281518110610daf57fe5b60209081029190910101516001600160a01b0390911690528251839083908110610dd557fe5b602002602001015160200151898281518110610ded57fe5b602090810291909101810151015260019182019101610d82565b50505050505050509695505050505050565b600080610e31848460200260040160ff166020611184565b9050610e4284600483016020611184565b949350505050565b60006103518260006103f6565b50601290565b600080836001600160a01b0316631e50a4a66040518163ffffffff1660e01b815260040160206040518083038186803b158015610e9957600080fd5b505afa158015610ead573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed191906130e5565b90506000816001600160a01b031663e5406dbf6040518163ffffffff1660e01b815260040160006040518083038186803b158015610f0e57600080fd5b505afa158015610f22573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f4a9190810190613323565b90506000806000806000806000808c6001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015610f9157600080fd5b505afa158015610fa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc991906130e5565b895190915060005b81811015611167578a8181518110610fe557fe5b6020026020010151600001519950826001600160a01b031663032c49ed8b6040518263ffffffff1660e01b815260040161101f919061374b565b60206040518083038186803b15801561103757600080fd5b505afa15801561104b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106f91906135c8565b61ffff166004141561115f576110858f8b6127cd565b9a5090975095508615158061109957508515155b1561115f5760405163b3596f0760e01b81526001600160a01b0384169063b3596f07906110ca908d9060040161374b565b60206040518083038186803b1580156110e257600080fd5b505afa1580156110f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111a91906135ea565b975061113e611137600a8b900a6111318b8b612a68565b90612ac1565b8690612b28565b945061115c611155600a8b900a6111318b8a612a68565b8590612b28565b93505b600101610fd1565b506111728484612b82565b9e9d5050505050505050505050505050565b6000818301845110156111de576040805162461bcd60e51b815260206004820152601b60248201527f52656164696e67206279746573206f7574206f6620626f756e64730000000000604482015290519081900360640190fd5b8260200184015190508160200380156111fd576008810260020a820491505b509392505050565b6001546001600160a01b031681565b60608182601f01101561125f576040805162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015290519081900360640190fd5b8282840110156112a7576040805162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015290519081900360640190fd5b818301845110156112f3576040805162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015290519081900360640190fd5b606082158015611312576040519150600082526020820160405261135c565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561134b578051835260209283019201611333565b5050858452601f01601f1916604052505b50949350505050565b60608060606000856001600160a01b0316631e50a4a66040518163ffffffff1660e01b815260040160206040518083038186803b1580156113a557600080fd5b505afa1580156113b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113dd91906130e5565b90506000816001600160a01b031663e5406dbf6040518163ffffffff1660e01b815260040160006040518083038186803b15801561141a57600080fd5b505afa15801561142e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114569190810190613323565b8051909150806001600160401b038111801561147157600080fd5b5060405190808252806020026020018201604052801561149b578160200160208202803683370190505b509550806001600160401b03811180156114b457600080fd5b506040519080825280602002602001820160405280156114de578160200160208202803683370190505b509450806001600160401b03811180156114f757600080fd5b50604051908082528060200260200182016040528015611521578160200160208202803683370190505b50935060008080805b8481101561188f5760005486516001600160a01b039091169063d2493b6c9088908490811061155557fe5b6020026020010151600001516040518263ffffffff1660e01b815260040161157d919061374b565b60606040518083038186803b15801561159557600080fd5b505afa1580156115a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115cd9190613139565b9095509350506001600160a01b03841615611743576040516370a0823160e01b81526001600160a01b038516906370a082319061160e908f9060040161374b565b60206040518083038186803b15801561162657600080fd5b505afa15801561163a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165e91906135ea565b89838151811061166a57fe5b60200260200101818152505088828151811061168257fe5b60200260200101516000146117435785818151811061169d57fe5b6020026020010151600001518a83815181106116b557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050611707670de0b6b3a76400006111318d8c86815181106116f157fe5b6020026020010151612a6890919063ffffffff16565b89838151811061171357fe5b602002602001018181525050600188838151811061172d57fe5b6020908102919091010152600190910190611887565b6001600160a01b03831615611887576040516370a0823160e01b81526001600160a01b038416906370a082319061177e908f9060040161374b565b60206040518083038186803b15801561179657600080fd5b505afa1580156117aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ce91906135ea565b8983815181106117da57fe5b6020026020010181815250508882815181106117f257fe5b60200260200101516000146118875785818151811061180d57fe5b6020026020010151600001518a838151811061182557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050611861670de0b6b3a76400006111318d8c86815181106116f157fe5b89838151811061186d57fe5b602002602001018181525050600288838151811061172d57fe5b60010161152a565b50600061189c8583612b82565b9050808a51038a52808951038952808851038852505050505050509250925092565b604080516001808252818301909252606091816020015b6118dd612f73565b8152602001906001900390816118d557505060015481519192506001600160a01b031690829060009061190c57fe5b6020908102919091018101516001600160a01b0390921690915260405160009161193a9185918991016138d6565b6040516020818303038152906040529050600085516001600160401b038111801561196457600080fd5b5060405190808252806020026020018201604052801561198e578160200160208202803683370190505b5090507fab9c4b5ddd7431ce4a1757257f6705ebcd264d177caf1ba9789e00504a5e74ef888787848c8760c46040516024016119d09796959493929190613793565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505083600081518110611a1057fe5b602002602001015160200181905250505095945050505050565b6060600080611a398685612bdf565b9150915081516002026001600160401b0381118015611a5757600080fd5b50604051908082528060200260200182016040528015611a9157816020015b611a7e612f73565b815260200190600190039081611a765790505b5092506000805b8351811015611c785760015485516001600160a01b0390911690869084908110611abe57fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f69328decb93fdb59917f0c50856674b0c726498e4b54e9d908efd10636a216d7848281518110611b0f57fe5b6020026020010151848381518110611b2357fe5b60200260200101518a604051602401611b3e93929190613845565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050858381518110611b7d57fe5b6020026020010151602001819052508180600101925050838181518110611ba057fe5b6020026020010151858381518110611bb457fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b87848381518110611c0657fe5b6020026020010151604051602401611c1f92919061382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050858381518110611c5e57fe5b602090810291909101810151015260019182019101611a98565b505050509392505050565b606083516002026001600160401b0381118015611c9f57600080fd5b50604051908082528060200260200182016040528015611cd957816020015b611cc6612f73565b815260200190600190039081611cbe5790505b5090506000805b8551811015611ebc57858181518110611cf557fe5b6020026020010151838381518110611d0957fe5b60209081029190910101516001600160a01b0391821690526001548651600080516020613aba833981519152929190911690879084908110611d4757fe5b6020026020010151604051602401611d6092919061382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050838381518110611d9f57fe5b602090810291909101810151015260018054845191909301926001600160a01b031690849084908110611dce57fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f573ade81da917875600753138ed8197ed3f106cda3a0b9d55b18d160638e02a9868281518110611e1f57fe5b6020026020010151868381518110611e3357fe5b6020026020010151868481518110611e4757fe5b60200260200101518a604051602401611e639493929190613898565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050838381518110611ea257fe5b602090810291909101810151015260019182019101611ce0565b5050949350505050565b6060600080611ed58787612bdf565b915091506000611ef060048451612a6890919063ffffffff16565b9050806001600160401b0381118015611f0857600080fd5b50604051908082528060200260200182016040528015611f4257816020015b611f2f612f73565b815260200190600190039081611f275790505b5060408051600280825260608201835292965060009290916020830190803683370190505090508581600181518110611f7757fe5b6001600160a01b03909216602092830291909101909101526000805b855181101561235a5760015487516001600160a01b0390911690889084908110611fb957fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f69328decb93fdb59917f0c50856674b0c726498e4b54e9d908efd10636a216d786828151811061200a57fe5b602002602001015186838151811061201e57fe5b60200260200101518d60405160240161203993929190613845565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505087838151811061207857fe5b6020026020010151602001819052508180600101925050876001600160a01b03168682815181106120a557fe5b60200260200101516001600160a01b031614612352578581815181106120c757fe5b60200260200101518783815181106120db57fe5b6020026020010151600001906001600160a01b031690816001600160a01b031681525050600080516020613aba8339815191528986838151811061211b57fe5b602002602001015160405160240161213492919061382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505087838151811061217357fe5b602002602001015160200181905250818060010192505085818151811061219657fe5b6020026020010151836000815181106121ab57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050888783815181106121d857fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f38ed1739ee07daf49933f1800d1a9bc8d39a6876ea11e643f9c4c39c66df0ee885828151811061222957fe5b60200260200101516000858e60001960405160240161224c9594939291906139d3565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505087838151811061228b57fe5b60200260200101516020018190525081806001019250508581815181106122ae57fe5b60200260200101518783815181106122c257fe5b60209081029190910101516001600160a01b039091169052604051600080516020613aba833981519152906122fe908b90600090602401613810565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505087838151811061233d57fe5b60209081029190910181015101526001909101905b600101611f93565b5060006123678483612b82565b875103875250949998505050505050505050565b6060600061239f600261239960028851612a6890919063ffffffff16565b90612b28565b9050806001600160401b03811180156123b757600080fd5b506040519080825280602002602001820160405280156123f157816020015b6123de612f73565b8152602001906001900390816123d65790505b506040805160028082526060820183529294506000929091602083019080368337019050509050868160008151811061242657fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060008784828151811061245557fe5b60209081029190910101516001600160a01b039091169052604051600080516020613aba83398151915290612492908b906000199060240161382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050508482815181106124d157fe5b602090810291909101810151015260010160005b87518110156127135760006125298783815181106124ff57fe5b602002602001015189848151811061251357fe5b6020026020010151612b2890919063ffffffff16565b9050896001600160a01b031689838151811061254157fe5b60200260200101516001600160a01b03161461265b5788828151811061256357fe5b60200260200101518460018151811061257857fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508a8684815181106125a557fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f8803dbeef1adfe1a9306daa835152093f0a5085700e080f4de0d56162dfadb0981600019868f600019604051602401612607959493929190613a12565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505086848151811061264657fe5b60209081029190910181015101526001909201915b88828151811061266757fe5b602002602001015186848151811061267b57fe5b60209081029190910101516001600160a01b039182169052600154604051600080516020613aba833981519152926126b9921690849060240161382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050508684815181106126f857fe5b602090810291909101810151015250600191820191016124e5565b508784828151811061272157fe5b60209081029190910101516001600160a01b039091169052604051600080516020613aba8339815191529061275d908b90600090602401613810565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505084828151811061279c57fe5b602090810291909101810151015260010160006127b98483612b82565b855103855250929998505050505050505050565b600080546040516334924edb60e21b8152829182918291829182916001600160a01b03169063d2493b6c90612806908a9060040161374b565b60606040518083038186803b15801561281e57600080fd5b505afa158015612832573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128569190613139565b919450925090506001600160a01b038316156129e8576040516370a0823160e01b81526001600160a01b038416906370a0823190612898908b9060040161374b565b60206040518083038186803b1580156128b057600080fd5b505afa1580156128c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e891906135ea565b95506129e5816001600160a01b03166370a082318a6040518263ffffffff1660e01b8152600401612919919061374b565b60206040518083038186803b15801561293157600080fd5b505afa158015612945573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296991906135ea565b6040516370a0823160e01b81526001600160a01b038516906370a0823190612995908d9060040161374b565b60206040518083038186803b1580156129ad57600080fd5b505afa1580156129c1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239991906135ea565b94505b866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612a2157600080fd5b505afa158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613602565b60ff1693505050509250925092565b600082612a7757506000610351565b82820282848281612a8457fe5b0414610a645760405162461bcd60e51b8152600401808060200182810382526021815260200180613a996021913960400191505060405180910390fd5b6000808211612b17576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381612b2057fe5b049392505050565b600082820183811015610a64576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115612bd9576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6060806000846001600160a01b0316631e50a4a66040518163ffffffff1660e01b815260040160206040518083038186803b158015612c1d57600080fd5b505afa158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5591906130e5565b90506000816001600160a01b031663e5406dbf6040518163ffffffff1660e01b815260040160006040518083038186803b158015612c9257600080fd5b505afa158015612ca6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612cce9190810190613323565b8051909150806001600160401b0381118015612ce957600080fd5b50604051908082528060200260200182016040528015612d13578160200160208202803683370190505b509450806001600160401b0381118015612d2c57600080fd5b50604051908082528060200260200182016040528015612d56578160200160208202803683370190505b50935060008060005b83811015612f4b5760005485516001600160a01b039091169063d2493b6c90879084908110612d8a57fe5b6020026020010151600001516040518263ffffffff1660e01b8152600401612db2919061374b565b60606040518083038186803b158015612dca57600080fd5b505afa158015612dde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e029190613139565b50909350506001600160a01b03831615612f43576040516370a0823160e01b81526001600160a01b038416906370a0823190612e42908d9060040161374b565b60206040518083038186803b158015612e5a57600080fd5b505afa158015612e6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9291906135ea565b878381518110612e9e57fe5b602002602001018181525050868281518110612eb657fe5b6020026020010151600014612f4357848181518110612ed157fe5b602002602001015160000151888381518110612ee957fe5b60200260200101906001600160a01b031690816001600160a01b031681525050612f25670de0b6b3a76400006111318b8a86815181106116f157fe5b878381518110612f3157fe5b60209081029190910101526001909101905b600101612d5f565b506000612f588483612b82565b90508088510388528087510387525050505050509250929050565b60408051808201909152600081526060602082015290565b80356103f181613a71565b600082601f830112612fa6578081fd5b81356020612fbb612fb683613a54565b613a31565b8281528181019085830183850287018401881015612fd7578586fd5b855b85811015612ffe578135612fec81613a71565b84529284019290840190600101612fd9565b5090979650505050505050565b600082601f83011261301b578081fd5b8135602061302b612fb683613a54565b8281528181019085830183850287018401881015613047578586fd5b855b85811015612ffe57813584529284019290840190600101613049565b600082601f830112613075578081fd5b81356001600160401b0381111561308857fe5b61309b601f8201601f1916602001613a31565b8181528460208386010111156130af578283fd5b816020850160208301379081016020019190915292915050565b6000602082840312156130da578081fd5b8135610a6481613a71565b6000602082840312156130f6578081fd5b8151610a6481613a71565b60008060408385031215613113578081fd5b823561311e81613a71565b9150602083013561312e81613a71565b809150509250929050565b60008060006060848603121561314d578081fd5b835161315881613a71565b602085015190935061316981613a71565b604085015190925061317a81613a71565b809150509250925092565b6000806000806060858703121561319a578081fd5b84356131a581613a71565b935060208501356131b581613a71565b925060408501356001600160401b03808211156131d0578283fd5b818701915087601f8301126131e3578283fd5b8135818111156131f1578384fd5b886020828501011115613202578384fd5b95989497505060200194505050565b60008060008060808587031215613226578182fd5b843561323181613a71565b9350602085013561324181613a71565b925060408501359150606085013561325881613a71565b939692955090935050565b60008060008060008060c0878903121561327b578384fd5b61328487612f8b565b95506020870135945060408701356001600160401b03808211156132a6578586fd5b6132b28a838b01612f96565b955060608901359150808211156132c7578384fd5b6132d38a838b0161300b565b945060808901359150808211156132e8578384fd5b6132f48a838b0161300b565b935060a0890135915080821115613309578283fd5b5061331689828a0161300b565b9150509295509295509295565b60006020808385031215613335578182fd5b82516001600160401b038082111561334b578384fd5b818501915085601f83011261335e578384fd5b815161336c612fb682613a54565b818152848101908486016040808502870188018b101561338a578889fd5b8896505b848710156133f15780828c0312156133a4578889fd5b805181810181811088821117156133b757fe5b825282516133c481613a71565b81528289015180151581146133d7578a8bfd5b818a0152845260019690960195928701929081019061338e565b50909998505050505050505050565b600060208284031215613411578081fd5b5035919050565b600060208284031215613429578081fd5b81356001600160401b0381111561343e578182fd5b610e4284828501613065565b6000806040838503121561345c578182fd5b82356001600160401b03811115613471578283fd5b61347d85828601613065565b95602094909401359450505050565b6000806000606084860312156134a0578081fd5b83356001600160401b038111156134b5578182fd5b6134c186828701613065565b9660208601359650604090950135949350505050565b600080604083850312156134e9578182fd5b82356001600160401b038111156134fe578283fd5b61350a85828601613065565b925050602083013561312e81613a89565b60008060006060848603121561352f578081fd5b83356001600160401b03811115613544578182fd5b61355086828701613065565b935050602084013561356181613a89565b929592945050506040919091013590565b600080600060608486031215613586578081fd5b83356001600160401b0381111561359b578182fd5b6135a786828701613065565b93505060208401356135b881613a89565b9150604084013561317a81613a89565b6000602082840312156135d9578081fd5b815161ffff81168114610a64578182fd5b6000602082840312156135fb578081fd5b5051919050565b600060208284031215613613578081fd5b8151610a6481613a89565b6000815180845260208085019450808401835b838110156136565781516001600160a01b031687529582019590820190600101613631565b509495945050505050565b6000815180845260208085018081965082840281019150828601855b858110156136c4578284038952815180516001600160a01b0316855285015160408686018190526136b081870183613700565b9a87019a955050509084019060010161367d565b5091979650505050505050565b6000815180845260208085019450808401835b83811015613656578151875295820195908201906001016136e4565b60008151808452815b8181101561372557602081850181015186830182015201613709565b818111156137365782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b600060018060a01b03808a16835260e060208401526137b560e084018a61361e565b83810360408501526137c7818a6136d1565b905083810360608501526137db81896136d1565b9050818716608085015283810360a08501526137f78187613700565b9250505060ff831660c083015298975050505050505050565b6001600160a01b0392909216825260ff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b600060018060a01b03851682528360208301526060604083015261388f6060830184613661565b95945050505050565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b600060208252610a646020830184613661565b6000604082526138e960408301856136d1565b90508260208301529392505050565b90815260200190565b6001600160e01b031991909116815260200190565b600060208252610a646020830184613700565b6020808252601d908201527f63616e6e6f742072656d6f7665206e6f6e2d656d707479206173736574000000604082015260600190565b6939bbb0b82937baba32b960b11b815260200190565b630eecae8d60e31b815260200190565b6020808252601c908201527f756e737570706f72746564207370656e64657220617070726f76616c00000000604082015260600190565b61ffff9290921682521515602082015260400190565b600086825260ff8616602083015260a060408301526139f560a083018661361e565b6001600160a01b0394909416606083015250608001529392505050565b600086825285602083015260a060408301526139f560a083018661361e565b6040518181016001600160401b0381118282101715613a4c57fe5b604052919050565b60006001600160401b03821115613a6757fe5b5060209081020190565b6001600160a01b0381168114613a8657600080fd5b50565b60ff81168114613a8657600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77095ea7b334ae44009aa867bfb386f5c3b4b443ac6f0ee573fa91c4608fbadfbaa26469706673582212206a54d0c3c980275ed7004f124414c95a767033a731a4aa3357d65fd7a85a061264736f6c6343000706003300000000000000000000000069fa688f1dc47d4b5d8029d5a35fb7a548310654000000000000000000000000794a61358d6845594f94dc1db02a252b5b4814ad

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101165760003560e01c80636f8ae202116100a2578063c3c6279f11610071578063c3c6279f14610270578063cf54aaa014610283578063d4fac45d14610296578063db896b57146102a9578063e9d337b8146102bc57610116565b80636f8ae2021461020857806382f86acc1461022a578063952bfb161461023d578063998546e31461025d57610116565b806341dc16c3116100e957806341dc16c3146101a45780635f9d4d2e146101b75780636179309d146101bf57806368901513146101e05780636d5fae54146101f357610116565b806309ff5c7d1461011b5780631053f952146101445780631eba307714610164578063293d806314610184575b600080fd5b61012e6101293660046134d7565b6102c4565b60405161013b91906138f8565b60405180910390f35b61015761015236600461351b565b610357565b60405161013b9190613916565b610177610172366004613400565b6103ef565b60405161013b919061374b565b61019761019236600461344a565b6103f6565b60405161013b9190613901565b61012e6101b2366004613572565b61045a565b610177610538565b6101d26101cd366004613185565b610547565b60405161013b9291906139bd565b6101576101ee366004613418565b6108ac565b610206610201366004613101565b6108c7565b005b61021b610216366004613211565b6108f8565b60405161013b93929190613868565b61012e6102383660046134d7565b610a4d565b61025061024b366004613263565b610a6b565b60405161013b91906138c3565b61012e61026b3660046134d7565b610e19565b61019761027e366004613418565b610e4a565b61012e6102913660046130c9565b610e57565b61012e6102a4366004613101565b610e5d565b61012e6102b736600461348c565b611184565b610177611205565b6000806102dc848460200260040160ff166020611184565b905060006102ef85600484016020611184565b905080610338576040805162461bcd60e51b8152602060048201526012602482015271696e707574206973206e6f7420617272617960701b604482015290519081900360640190fd5b61034c856020808402850160040190611184565b925050505b92915050565b60606014821061039f576040805162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a59081bd9999cd95d60921b604482015290519081900360640190fd5b81602002915060006103be85848660200260040160ff16016020611184565b905060006103d3868584016004016020611184565b90506103e58660248487010183611214565b9695505050505050565b805b919050565b60008160040183511015610451576040805162461bcd60e51b815260206004820152601b60248201527f52656164696e67206279746573206f7574206f6620626f756e64730000000000604482015290519081900360640190fd5b50016020015190565b600080610472858560200260040160ff166020611184565b9050600061048586600484016020611184565b9050806104ce576040805162461bcd60e51b8152602060048201526012602482015271696e707574206973206e6f7420617272617960701b604482015290519081900360640190fd5b60ff8416811161051e576040805162461bcd60e51b815260206004820152601660248201527534b73b30b634b21030b93930bc903837b9b4ba34b7b760511b604482015290519081900360640190fd5b6103e5866020600160ff8816018102850160040190611184565b6000546001600160a01b031681565b600080600061058b85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610e4a92505050565b90506001600160e01b0319811663095ea7b360e01b141561089e5760006105ea61017287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509250610a4d915050565b9050600061063087878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610a4d915050565b60001c905060008990506000816001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b15801561067557600080fd5b505afa158015610689573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ad91906130e5565b90506000816001600160a01b0316634f8419b9866040518263ffffffff1660e01b81526004016106dd919061374b565b60206040518083038186803b1580156106f557600080fd5b505afa158015610709573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072d91906130e5565b90506001600160a01b0381161580159061075057506001600160a01b0381163014155b6107755760405162461bcd60e51b815260040161076c90613986565b60405180910390fd5b7f5343b378d69227c1bc2016fd44e8104f0ffa7729f4f4f4110e349a2db0a0d0c8836001600160a01b03166339b81fd96040518163ffffffff1660e01b815260040160206040518083038186803b1580156107cf57600080fd5b505afa1580156107e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080791906130e5565b8d6001600160a01b031663481c6a756040518163ffffffff1660e01b815260040160206040518083038186803b15801561084057600080fd5b505afa158015610854573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087891906130e5565b87874260405161088c95949392919061375f565b60405180910390a16001975050505050505b506000905094509492505050565b6060610351600480845103846112149092919063ffffffff16565b60006108d38383610e5d565b905080156108f35760405162461bcd60e51b815260040161076c90613929565b505050565b6000806060600080600061090c8a89611365565b925092509250600083511115610a2b5760008a6001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b15801561095757600080fd5b505afa15801561096b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098f91906130e5565b6040516321f8a72160e01b81529091506001600160a01b038216906321f8a721906109bc90600401613976565b60206040518083038186803b1580156109d457600080fd5b505afa1580156109e8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0c91906130e5565b9650610a1b8b8a8686866118be565b600096509450610a439350505050565b610a368a888a611a2a565b9350600080955095505050505b9450945094915050565b6000610a64838360200260040160ff166020611184565b9392505050565b60606000876001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015610aa857600080fd5b505afa158015610abc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae091906130e5565b90506000816001600160a01b03166321f8a7216040518163ffffffff1660e01b8152600401610b0e90613960565b60206040518083038186803b158015610b2657600080fd5b505afa158015610b3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5e91906130e5565b90506000826001600160a01b03166321f8a7216040518163ffffffff1660e01b8152600401610b8c90613976565b60206040518083038186803b158015610ba457600080fd5b505afa158015610bb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bdc91906130e5565b90506000610bec8b8a8a89611c83565b90506000610bfc8c8c8686611ec6565b90506000610c0e8d86868e8e8e61237b565b905080518251845101016001600160401b0381118015610c2d57600080fd5b50604051908082528060200260200182016040528015610c6757816020015b610c54612f73565b815260200190600190039081610c4c5790505b5096506000805b8451821015610cf357848281518110610c8357fe5b602002602001015160000151898281518110610c9b57fe5b60209081029190910101516001600160a01b0390911690528451859083908110610cc157fe5b602002602001015160200151898281518110610cd957fe5b602090810291909101810151015260019182019101610c6e565b600091505b8351821015610d7d57838281518110610d0d57fe5b602002602001015160000151898281518110610d2557fe5b60209081029190910101516001600160a01b0390911690528351849083908110610d4b57fe5b602002602001015160200151898281518110610d6357fe5b602090810291909101810151015260019182019101610cf8565b600091505b8251821015610e0757828281518110610d9757fe5b602002602001015160000151898281518110610daf57fe5b60209081029190910101516001600160a01b0390911690528251839083908110610dd557fe5b602002602001015160200151898281518110610ded57fe5b602090810291909101810151015260019182019101610d82565b50505050505050509695505050505050565b600080610e31848460200260040160ff166020611184565b9050610e4284600483016020611184565b949350505050565b60006103518260006103f6565b50601290565b600080836001600160a01b0316631e50a4a66040518163ffffffff1660e01b815260040160206040518083038186803b158015610e9957600080fd5b505afa158015610ead573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed191906130e5565b90506000816001600160a01b031663e5406dbf6040518163ffffffff1660e01b815260040160006040518083038186803b158015610f0e57600080fd5b505afa158015610f22573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f4a9190810190613323565b90506000806000806000806000808c6001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015610f9157600080fd5b505afa158015610fa5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc991906130e5565b895190915060005b81811015611167578a8181518110610fe557fe5b6020026020010151600001519950826001600160a01b031663032c49ed8b6040518263ffffffff1660e01b815260040161101f919061374b565b60206040518083038186803b15801561103757600080fd5b505afa15801561104b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106f91906135c8565b61ffff166004141561115f576110858f8b6127cd565b9a5090975095508615158061109957508515155b1561115f5760405163b3596f0760e01b81526001600160a01b0384169063b3596f07906110ca908d9060040161374b565b60206040518083038186803b1580156110e257600080fd5b505afa1580156110f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111a91906135ea565b975061113e611137600a8b900a6111318b8b612a68565b90612ac1565b8690612b28565b945061115c611155600a8b900a6111318b8a612a68565b8590612b28565b93505b600101610fd1565b506111728484612b82565b9e9d5050505050505050505050505050565b6000818301845110156111de576040805162461bcd60e51b815260206004820152601b60248201527f52656164696e67206279746573206f7574206f6620626f756e64730000000000604482015290519081900360640190fd5b8260200184015190508160200380156111fd576008810260020a820491505b509392505050565b6001546001600160a01b031681565b60608182601f01101561125f576040805162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015290519081900360640190fd5b8282840110156112a7576040805162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b604482015290519081900360640190fd5b818301845110156112f3576040805162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b604482015290519081900360640190fd5b606082158015611312576040519150600082526020820160405261135c565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561134b578051835260209283019201611333565b5050858452601f01601f1916604052505b50949350505050565b60608060606000856001600160a01b0316631e50a4a66040518163ffffffff1660e01b815260040160206040518083038186803b1580156113a557600080fd5b505afa1580156113b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113dd91906130e5565b90506000816001600160a01b031663e5406dbf6040518163ffffffff1660e01b815260040160006040518083038186803b15801561141a57600080fd5b505afa15801561142e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526114569190810190613323565b8051909150806001600160401b038111801561147157600080fd5b5060405190808252806020026020018201604052801561149b578160200160208202803683370190505b509550806001600160401b03811180156114b457600080fd5b506040519080825280602002602001820160405280156114de578160200160208202803683370190505b509450806001600160401b03811180156114f757600080fd5b50604051908082528060200260200182016040528015611521578160200160208202803683370190505b50935060008080805b8481101561188f5760005486516001600160a01b039091169063d2493b6c9088908490811061155557fe5b6020026020010151600001516040518263ffffffff1660e01b815260040161157d919061374b565b60606040518083038186803b15801561159557600080fd5b505afa1580156115a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115cd9190613139565b9095509350506001600160a01b03841615611743576040516370a0823160e01b81526001600160a01b038516906370a082319061160e908f9060040161374b565b60206040518083038186803b15801561162657600080fd5b505afa15801561163a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165e91906135ea565b89838151811061166a57fe5b60200260200101818152505088828151811061168257fe5b60200260200101516000146117435785818151811061169d57fe5b6020026020010151600001518a83815181106116b557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050611707670de0b6b3a76400006111318d8c86815181106116f157fe5b6020026020010151612a6890919063ffffffff16565b89838151811061171357fe5b602002602001018181525050600188838151811061172d57fe5b6020908102919091010152600190910190611887565b6001600160a01b03831615611887576040516370a0823160e01b81526001600160a01b038416906370a082319061177e908f9060040161374b565b60206040518083038186803b15801561179657600080fd5b505afa1580156117aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ce91906135ea565b8983815181106117da57fe5b6020026020010181815250508882815181106117f257fe5b60200260200101516000146118875785818151811061180d57fe5b6020026020010151600001518a838151811061182557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050611861670de0b6b3a76400006111318d8c86815181106116f157fe5b89838151811061186d57fe5b602002602001018181525050600288838151811061172d57fe5b60010161152a565b50600061189c8583612b82565b9050808a51038a52808951038952808851038852505050505050509250925092565b604080516001808252818301909252606091816020015b6118dd612f73565b8152602001906001900390816118d557505060015481519192506001600160a01b031690829060009061190c57fe5b6020908102919091018101516001600160a01b0390921690915260405160009161193a9185918991016138d6565b6040516020818303038152906040529050600085516001600160401b038111801561196457600080fd5b5060405190808252806020026020018201604052801561198e578160200160208202803683370190505b5090507fab9c4b5ddd7431ce4a1757257f6705ebcd264d177caf1ba9789e00504a5e74ef888787848c8760c46040516024016119d09796959493929190613793565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505083600081518110611a1057fe5b602002602001015160200181905250505095945050505050565b6060600080611a398685612bdf565b9150915081516002026001600160401b0381118015611a5757600080fd5b50604051908082528060200260200182016040528015611a9157816020015b611a7e612f73565b815260200190600190039081611a765790505b5092506000805b8351811015611c785760015485516001600160a01b0390911690869084908110611abe57fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f69328decb93fdb59917f0c50856674b0c726498e4b54e9d908efd10636a216d7848281518110611b0f57fe5b6020026020010151848381518110611b2357fe5b60200260200101518a604051602401611b3e93929190613845565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050858381518110611b7d57fe5b6020026020010151602001819052508180600101925050838181518110611ba057fe5b6020026020010151858381518110611bb457fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507fa9059cbb2ab09eb219583f4a59a5d0623ade346d962bcd4e46b11da047c9049b87848381518110611c0657fe5b6020026020010151604051602401611c1f92919061382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050858381518110611c5e57fe5b602090810291909101810151015260019182019101611a98565b505050509392505050565b606083516002026001600160401b0381118015611c9f57600080fd5b50604051908082528060200260200182016040528015611cd957816020015b611cc6612f73565b815260200190600190039081611cbe5790505b5090506000805b8551811015611ebc57858181518110611cf557fe5b6020026020010151838381518110611d0957fe5b60209081029190910101516001600160a01b0391821690526001548651600080516020613aba833981519152929190911690879084908110611d4757fe5b6020026020010151604051602401611d6092919061382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050838381518110611d9f57fe5b602090810291909101810151015260018054845191909301926001600160a01b031690849084908110611dce57fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f573ade81da917875600753138ed8197ed3f106cda3a0b9d55b18d160638e02a9868281518110611e1f57fe5b6020026020010151868381518110611e3357fe5b6020026020010151868481518110611e4757fe5b60200260200101518a604051602401611e639493929190613898565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050838381518110611ea257fe5b602090810291909101810151015260019182019101611ce0565b5050949350505050565b6060600080611ed58787612bdf565b915091506000611ef060048451612a6890919063ffffffff16565b9050806001600160401b0381118015611f0857600080fd5b50604051908082528060200260200182016040528015611f4257816020015b611f2f612f73565b815260200190600190039081611f275790505b5060408051600280825260608201835292965060009290916020830190803683370190505090508581600181518110611f7757fe5b6001600160a01b03909216602092830291909101909101526000805b855181101561235a5760015487516001600160a01b0390911690889084908110611fb957fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f69328decb93fdb59917f0c50856674b0c726498e4b54e9d908efd10636a216d786828151811061200a57fe5b602002602001015186838151811061201e57fe5b60200260200101518d60405160240161203993929190613845565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505087838151811061207857fe5b6020026020010151602001819052508180600101925050876001600160a01b03168682815181106120a557fe5b60200260200101516001600160a01b031614612352578581815181106120c757fe5b60200260200101518783815181106120db57fe5b6020026020010151600001906001600160a01b031690816001600160a01b031681525050600080516020613aba8339815191528986838151811061211b57fe5b602002602001015160405160240161213492919061382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505087838151811061217357fe5b602002602001015160200181905250818060010192505085818151811061219657fe5b6020026020010151836000815181106121ab57fe5b60200260200101906001600160a01b031690816001600160a01b031681525050888783815181106121d857fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f38ed1739ee07daf49933f1800d1a9bc8d39a6876ea11e643f9c4c39c66df0ee885828151811061222957fe5b60200260200101516000858e60001960405160240161224c9594939291906139d3565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505087838151811061228b57fe5b60200260200101516020018190525081806001019250508581815181106122ae57fe5b60200260200101518783815181106122c257fe5b60209081029190910101516001600160a01b039091169052604051600080516020613aba833981519152906122fe908b90600090602401613810565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505087838151811061233d57fe5b60209081029190910181015101526001909101905b600101611f93565b5060006123678483612b82565b875103875250949998505050505050505050565b6060600061239f600261239960028851612a6890919063ffffffff16565b90612b28565b9050806001600160401b03811180156123b757600080fd5b506040519080825280602002602001820160405280156123f157816020015b6123de612f73565b8152602001906001900390816123d65790505b506040805160028082526060820183529294506000929091602083019080368337019050509050868160008151811061242657fe5b60200260200101906001600160a01b031690816001600160a01b03168152505060008784828151811061245557fe5b60209081029190910101516001600160a01b039091169052604051600080516020613aba83398151915290612492908b906000199060240161382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050508482815181106124d157fe5b602090810291909101810151015260010160005b87518110156127135760006125298783815181106124ff57fe5b602002602001015189848151811061251357fe5b6020026020010151612b2890919063ffffffff16565b9050896001600160a01b031689838151811061254157fe5b60200260200101516001600160a01b03161461265b5788828151811061256357fe5b60200260200101518460018151811061257857fe5b60200260200101906001600160a01b031690816001600160a01b0316815250508a8684815181106125a557fe5b6020026020010151600001906001600160a01b031690816001600160a01b0316815250507f8803dbeef1adfe1a9306daa835152093f0a5085700e080f4de0d56162dfadb0981600019868f600019604051602401612607959493929190613a12565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505086848151811061264657fe5b60209081029190910181015101526001909201915b88828151811061266757fe5b602002602001015186848151811061267b57fe5b60209081029190910101516001600160a01b039182169052600154604051600080516020613aba833981519152926126b9921690849060240161382c565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b0383818316178352505050508684815181106126f857fe5b602090810291909101810151015250600191820191016124e5565b508784828151811061272157fe5b60209081029190910101516001600160a01b039091169052604051600080516020613aba8339815191529061275d908b90600090602401613810565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b03838183161783525050505084828151811061279c57fe5b602090810291909101810151015260010160006127b98483612b82565b855103855250929998505050505050505050565b600080546040516334924edb60e21b8152829182918291829182916001600160a01b03169063d2493b6c90612806908a9060040161374b565b60606040518083038186803b15801561281e57600080fd5b505afa158015612832573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128569190613139565b919450925090506001600160a01b038316156129e8576040516370a0823160e01b81526001600160a01b038416906370a0823190612898908b9060040161374b565b60206040518083038186803b1580156128b057600080fd5b505afa1580156128c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e891906135ea565b95506129e5816001600160a01b03166370a082318a6040518263ffffffff1660e01b8152600401612919919061374b565b60206040518083038186803b15801561293157600080fd5b505afa158015612945573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296991906135ea565b6040516370a0823160e01b81526001600160a01b038516906370a0823190612995908d9060040161374b565b60206040518083038186803b1580156129ad57600080fd5b505afa1580156129c1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061239991906135ea565b94505b866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612a2157600080fd5b505afa158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613602565b60ff1693505050509250925092565b600082612a7757506000610351565b82820282848281612a8457fe5b0414610a645760405162461bcd60e51b8152600401808060200182810382526021815260200180613a996021913960400191505060405180910390fd5b6000808211612b17576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381612b2057fe5b049392505050565b600082820183811015610a64576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082821115612bd9576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6060806000846001600160a01b0316631e50a4a66040518163ffffffff1660e01b815260040160206040518083038186803b158015612c1d57600080fd5b505afa158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5591906130e5565b90506000816001600160a01b031663e5406dbf6040518163ffffffff1660e01b815260040160006040518083038186803b158015612c9257600080fd5b505afa158015612ca6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612cce9190810190613323565b8051909150806001600160401b0381118015612ce957600080fd5b50604051908082528060200260200182016040528015612d13578160200160208202803683370190505b509450806001600160401b0381118015612d2c57600080fd5b50604051908082528060200260200182016040528015612d56578160200160208202803683370190505b50935060008060005b83811015612f4b5760005485516001600160a01b039091169063d2493b6c90879084908110612d8a57fe5b6020026020010151600001516040518263ffffffff1660e01b8152600401612db2919061374b565b60606040518083038186803b158015612dca57600080fd5b505afa158015612dde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e029190613139565b50909350506001600160a01b03831615612f43576040516370a0823160e01b81526001600160a01b038416906370a0823190612e42908d9060040161374b565b60206040518083038186803b158015612e5a57600080fd5b505afa158015612e6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9291906135ea565b878381518110612e9e57fe5b602002602001018181525050868281518110612eb657fe5b6020026020010151600014612f4357848181518110612ed157fe5b602002602001015160000151888381518110612ee957fe5b60200260200101906001600160a01b031690816001600160a01b031681525050612f25670de0b6b3a76400006111318b8a86815181106116f157fe5b878381518110612f3157fe5b60209081029190910101526001909101905b600101612d5f565b506000612f588483612b82565b90508088510388528087510387525050505050509250929050565b60408051808201909152600081526060602082015290565b80356103f181613a71565b600082601f830112612fa6578081fd5b81356020612fbb612fb683613a54565b613a31565b8281528181019085830183850287018401881015612fd7578586fd5b855b85811015612ffe578135612fec81613a71565b84529284019290840190600101612fd9565b5090979650505050505050565b600082601f83011261301b578081fd5b8135602061302b612fb683613a54565b8281528181019085830183850287018401881015613047578586fd5b855b85811015612ffe57813584529284019290840190600101613049565b600082601f830112613075578081fd5b81356001600160401b0381111561308857fe5b61309b601f8201601f1916602001613a31565b8181528460208386010111156130af578283fd5b816020850160208301379081016020019190915292915050565b6000602082840312156130da578081fd5b8135610a6481613a71565b6000602082840312156130f6578081fd5b8151610a6481613a71565b60008060408385031215613113578081fd5b823561311e81613a71565b9150602083013561312e81613a71565b809150509250929050565b60008060006060848603121561314d578081fd5b835161315881613a71565b602085015190935061316981613a71565b604085015190925061317a81613a71565b809150509250925092565b6000806000806060858703121561319a578081fd5b84356131a581613a71565b935060208501356131b581613a71565b925060408501356001600160401b03808211156131d0578283fd5b818701915087601f8301126131e3578283fd5b8135818111156131f1578384fd5b886020828501011115613202578384fd5b95989497505060200194505050565b60008060008060808587031215613226578182fd5b843561323181613a71565b9350602085013561324181613a71565b925060408501359150606085013561325881613a71565b939692955090935050565b60008060008060008060c0878903121561327b578384fd5b61328487612f8b565b95506020870135945060408701356001600160401b03808211156132a6578586fd5b6132b28a838b01612f96565b955060608901359150808211156132c7578384fd5b6132d38a838b0161300b565b945060808901359150808211156132e8578384fd5b6132f48a838b0161300b565b935060a0890135915080821115613309578283fd5b5061331689828a0161300b565b9150509295509295509295565b60006020808385031215613335578182fd5b82516001600160401b038082111561334b578384fd5b818501915085601f83011261335e578384fd5b815161336c612fb682613a54565b818152848101908486016040808502870188018b101561338a578889fd5b8896505b848710156133f15780828c0312156133a4578889fd5b805181810181811088821117156133b757fe5b825282516133c481613a71565b81528289015180151581146133d7578a8bfd5b818a0152845260019690960195928701929081019061338e565b50909998505050505050505050565b600060208284031215613411578081fd5b5035919050565b600060208284031215613429578081fd5b81356001600160401b0381111561343e578182fd5b610e4284828501613065565b6000806040838503121561345c578182fd5b82356001600160401b03811115613471578283fd5b61347d85828601613065565b95602094909401359450505050565b6000806000606084860312156134a0578081fd5b83356001600160401b038111156134b5578182fd5b6134c186828701613065565b9660208601359650604090950135949350505050565b600080604083850312156134e9578182fd5b82356001600160401b038111156134fe578283fd5b61350a85828601613065565b925050602083013561312e81613a89565b60008060006060848603121561352f578081fd5b83356001600160401b03811115613544578182fd5b61355086828701613065565b935050602084013561356181613a89565b929592945050506040919091013590565b600080600060608486031215613586578081fd5b83356001600160401b0381111561359b578182fd5b6135a786828701613065565b93505060208401356135b881613a89565b9150604084013561317a81613a89565b6000602082840312156135d9578081fd5b815161ffff81168114610a64578182fd5b6000602082840312156135fb578081fd5b5051919050565b600060208284031215613613578081fd5b8151610a6481613a89565b6000815180845260208085019450808401835b838110156136565781516001600160a01b031687529582019590820190600101613631565b509495945050505050565b6000815180845260208085018081965082840281019150828601855b858110156136c4578284038952815180516001600160a01b0316855285015160408686018190526136b081870183613700565b9a87019a955050509084019060010161367d565b5091979650505050505050565b6000815180845260208085019450808401835b83811015613656578151875295820195908201906001016136e4565b60008151808452815b8181101561372557602081850181015186830182015201613709565b818111156137365782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b600060018060a01b03808a16835260e060208401526137b560e084018a61361e565b83810360408501526137c7818a6136d1565b905083810360608501526137db81896136d1565b9050818716608085015283810360a08501526137f78187613700565b9250505060ff831660c083015298975050505050505050565b6001600160a01b0392909216825260ff16602082015260400190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b600060018060a01b03851682528360208301526060604083015261388f6060830184613661565b95945050505050565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b600060208252610a646020830184613661565b6000604082526138e960408301856136d1565b90508260208301529392505050565b90815260200190565b6001600160e01b031991909116815260200190565b600060208252610a646020830184613700565b6020808252601d908201527f63616e6e6f742072656d6f7665206e6f6e2d656d707479206173736574000000604082015260600190565b6939bbb0b82937baba32b960b11b815260200190565b630eecae8d60e31b815260200190565b6020808252601c908201527f756e737570706f72746564207370656e64657220617070726f76616c00000000604082015260600190565b61ffff9290921682521515602082015260400190565b600086825260ff8616602083015260a060408301526139f560a083018661361e565b6001600160a01b0394909416606083015250608001529392505050565b600086825285602083015260a060408301526139f560a083018661361e565b6040518181016001600160401b0381118282101715613a4c57fe5b604052919050565b60006001600160401b03821115613a6757fe5b5060209081020190565b6001600160a01b0381168114613a8657600080fd5b50565b60ff81168114613a8657600080fdfe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77095ea7b334ae44009aa867bfb386f5c3b4b443ac6f0ee573fa91c4608fbadfbaa26469706673582212206a54d0c3c980275ed7004f124414c95a767033a731a4aa3357d65fd7a85a061264736f6c63430007060033

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

00000000000000000000000069fa688f1dc47d4b5d8029d5a35fb7a548310654000000000000000000000000794a61358d6845594f94dc1db02a252b5b4814ad

-----Decoded View---------------
Arg [0] : _aaveProtocolDataProvider (address): 0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654
Arg [1] : _aaveLendingPool (address): 0x794a61358D6845594F94dc1DB02A252b5b4814aD

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000069fa688f1dc47d4b5d8029d5a35fb7a548310654
Arg [1] : 000000000000000000000000794a61358d6845594f94dc1db02a252b5b4814ad


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.