ETH Price: $3,082.72 (-1.66%)

Token

TRSY (TRSY)
 

Overview

Max Total Supply

1,031,406.156373818536688248 TRSY

Holders

605 ( 0.331%)

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
1.288442265783499154 TRSY

Value
$0.00
0xa97e9ba560042d1141b344dbdbc5915ad9fbb88e
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Fyde enables the crypto ecosystem to diversify portfolios & treasuries, unlock token liquidity, and generate yield while retaining governance rights. The protocol introduces an innovation of the Liquid Vault that creates large multi-asset liquidity vaults directly accessible by governance token.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Fyde

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 36 : Fyde.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

/// Import from Core /////
import {TRSY} from "./core/TRSY.sol";
import {AssetRegistry} from "./core/AssetRegistry.sol";
import {AddressRegistry} from "./core/AddressRegistry.sol";
import {ProtocolState} from "./core/ProtocolState.sol";
import {Tax} from "./core/Tax.sol";
import {GovernanceAccess} from "./core/GovernanceAccess.sol";

/// Structs /////
import {RequestData, ProcessParam, AssetInfo} from "./core/Structs.sol";

/// Utils /////
import {Ownable} from "./utils/Ownable.sol";
import {PercentageMath} from "./utils/PercentageMath.sol";
import {SafeERC20} from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";

//Interfaces
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";
import {IOracle} from "src/interfaces/IOracle.sol";
import {IRelayer} from "src/interfaces/IRelayer.sol";

///@title Fyde contract
///@notice Fyde is the main contract of the protocol, it handles logic of deposit and withdraw in
/// the protocol
///        Deposit and withdraw occurs a mint or a burn of TRSY (ERC20 that represent shares of the
/// procotol in USD value)
///        Users can both deposit/withdraw in standard or governance pool
contract Fyde is TRSY, AddressRegistry, ProtocolState, AssetRegistry, GovernanceAccess, Tax {
  using SafeERC20 for IERC20;
  /*//////////////////////////////////////////////////////////////
                            EVENTS
  //////////////////////////////////////////////////////////////*/

  event FeesCollected(address indexed recipient, uint256 trsyFeesCollected);
  event Deposit(uint32 requestId, uint256 trsyPrice, uint256 usdDepositValue, uint256 trsyMinted);
  event Withdraw(uint32 requestId, uint256 trsyPrice, uint256 usdWithdrawValue, uint256 trsyBurned);
  event Swap(uint32 requestId, address assetOut, uint256 amountOut);
  event ManagementFeeCollected(uint256 feeToMint);

  /*//////////////////////////////////////////////////////////////
                              ERROR
  //////////////////////////////////////////////////////////////*/

  error AumNotInRange();
  error OnlyOneUpdatePerBlock();
  error SlippageExceed();
  error FydeBalanceInsufficient();
  error InsufficientTRSYBalance();
  error AssetPriceNotAvailable();
  error SwapAmountNotAvailable();
  error AssetNotSupported(address asset);
  error SwapDisabled(address asset);
  error AssetIsQuarantined(address asset);

  /*//////////////////////////////////////////////////////////////
                            CONSTRUCTOR
  //////////////////////////////////////////////////////////////*/

  constructor(
    address _relayer,
    address _oracleModule,
    address _governanceModule,
    uint16 _maxAumDeviationAllowed,
    uint72 _taxFactor,
    uint72 _managementFee
  ) Ownable(msg.sender) AddressRegistry(_governanceModule, _relayer) {
    oracleModule = IOracle(_oracleModule);
    updateMaxAumDeviationAllowed(_maxAumDeviationAllowed);
    updateTaxFactor(_taxFactor);
    updateManagementFee(_managementFee);
    _updateLastFeeCollectionTime();
  }

  /*//////////////////////////////////////////////////////////////
                                AUTH
  //////////////////////////////////////////////////////////////*/

  ///@notice Collect and send TRSY fees (from tax fees) to an external address
  ///@param _recipient Address to send TRSY fees to
  ///@param _amount Amount of TRSY to send
  function collectFees(address _recipient, uint256 _amount) external onlyOwner {
    _checkZeroAddress(_recipient);
    _checkZeroValue(_amount);
    balanceOf[address(this)] -= _amount;
    balanceOf[_recipient] += _amount;
    emit FeesCollected(_recipient, _amount);
  }

  ///@notice Collect management fee by inflating TRSY and minting to Fyde
  ///        is called by the relayer when processingRequests
  function collectManagementFee() external {
    uint256 feePerSecond = uint256(protocolData.managementFee / 31_557_600);
    uint256 timePeriod = block.timestamp - protocolData.lastFeeCollectionTime;
    if (timePeriod == 0) return;
    uint256 feeToMint = feePerSecond * timePeriod * totalSupply / 1e18;
    _updateLastFeeCollectionTime();
    _mint(address(this), feeToMint);
    emit ManagementFeeCollected(feeToMint);
  }

  /*//////////////////////////////////////////////////////////////
                  RELAYER & KEEPER FUNCTIONS
  //////////////////////////////////////////////////////////////*/

  ///@notice Update protocol AUM, called by keeper
  ///@param _aum New AUM
  ///@dev Can at most be updated by maxDeviationThreshold and only once per block
  function updateProtocolAUM(uint256 _aum) external {
    if (msg.sender != RELAYER && msg.sender != owner) revert Unauthorized();
    if (block.number == protocolData.lastAUMUpdateBlock) revert CoolDownPeriodActive();
    protocolData.lastAUMUpdateBlock = uint48(block.number);
    (, uint256 limitedAum) = _AumIsInRange(_aum);
    _updateProtocolAUM(limitedAum);
  }

  /*//////////////////////////////////////////////////////////////
                  PROCESSING DEPOSIT ACTIONS
  //////////////////////////////////////////////////////////////*/

  ///@notice Process deposit action, called by relayer
  ///@param _protocolAUM AUM given by keeper
  ///@param _req RequestData struct
  ///@return totalUsdDeposit USD value of the deposit
  function processDeposit(uint256 _protocolAUM, RequestData calldata _req)
    external
    onlyRelayer
    returns (uint256)
  {
    // Check if asset is supported
    _checkIsSupported(_req.assetIn);
    _checkIsNotQuarantined(_req.assetIn);

    // is keeper AUM in range
    (bool isInRange,) = _AumIsInRange(_protocolAUM);
    if (!isInRange) revert AumNotInRange();

    (
      ProcessParam[] memory processParam,
      uint256 sharesToMint,
      uint256 taxInTRSY,
      uint256 totalUsdDeposit
    ) = getProcessParamDeposit(_req, _protocolAUM);

    // Slippage checker
    if (_req.slippageChecker > sharesToMint) revert SlippageExceed();

    // Transfer assets to Fyde
    for (uint256 i; i < _req.assetIn.length; i++) {
      IERC20(_req.assetIn[i]).safeTransferFrom(_req.requestor, address(this), _req.amountIn[i]);
    }

    if (_req.keepGovRights) _govDeposit(_req, processParam);
    else _standardDeposit(_req, sharesToMint);

    // Mint tax and keep in contract
    if (taxInTRSY > 0) _mint(address(this), taxInTRSY);
    _updateProtocolAUM(_protocolAUM + totalUsdDeposit);

    uint256 trsyPrice = (1e18 * (_protocolAUM + totalUsdDeposit)) / totalSupply;
    emit Deposit(_req.id, trsyPrice, totalUsdDeposit, sharesToMint);
    return totalUsdDeposit;
  }

  function _standardDeposit(RequestData calldata _req, uint256 _sharesToMint) internal {
    // Accounting
    _increaseAssetTotalAmount(_req.assetIn, _req.amountIn);

    // Minting shares
    _mint(_req.requestor, _sharesToMint);
  }

  function _govDeposit(RequestData calldata _req, ProcessParam[] memory _processParam) internal {
    uint256[] memory sharesAfterTax = new uint256[](_req.assetIn.length);
    uint256[] memory amountInAfterTax = new uint256[](_req.assetIn.length);
    // Same average tax rate is applied to each asset
    uint256 taxMultiplicator;
    uint256 totalTrsy;
    for (uint256 i; i < _req.assetIn.length; i++) {
      taxMultiplicator = 1e18 * _processParam[i].sharesAfterTax / (_processParam[i].sharesBeforeTax);
      amountInAfterTax[i] = _req.amountIn[i] * taxMultiplicator / 1e18;
      sharesAfterTax[i] = _processParam[i].sharesAfterTax;
      totalTrsy += sharesAfterTax[i];
    }

    // Mint stTRSY and transfer token into proxy
    address proxy = GOVERNANCE_MODULE.govDeposit(
      _req.requestor, _req.assetIn, amountInAfterTax, sharesAfterTax, totalTrsy
    );

    for (uint256 i; i < _req.assetIn.length; i++) {
      IERC20(_req.assetIn[i]).safeTransfer(proxy, amountInAfterTax[i]);
    }

    // Accounting
    _increaseAssetTotalAmount(_req.assetIn, _req.amountIn);
    _increaseAssetProxyAmount(_req.assetIn, amountInAfterTax);

    // Mint
    _mint(address(GOVERNANCE_MODULE), totalTrsy);
  }

  /*//////////////////////////////////////////////////////////////
                  PROCESSING WITHDRAW ACTIONS
  //////////////////////////////////////////////////////////////*/

  ///@notice Process withdraw action, called by relayer
  ///@param _protocolAUM AUM given by keeper
  ///@param _req RequestData struct
  ///@return totalUsdWithdraw USD value of the withdraw
  function processWithdraw(uint256 _protocolAUM, RequestData calldata _req)
    external
    onlyRelayer
    returns (uint256)
  {
    // Check if asset is supported
    _checkIsSupported(_req.assetOut);
    _checkIsNotQuarantined(_req.assetOut);

    // is keeper AUM in range
    (bool isInRange,) = _AumIsInRange(_protocolAUM);
    if (!isInRange) revert AumNotInRange();

    uint256 totalUsdWithdraw;
    uint256 totalSharesToBurn;

    (totalUsdWithdraw, totalSharesToBurn) =
      _req.keepGovRights ? _govWithdraw(_protocolAUM, _req) : _standardWithdraw(_protocolAUM, _req);

    // Accounting
    _decreaseAssetTotalAmount(_req.assetOut, _req.amountOut);
    _updateProtocolAUM(_protocolAUM - totalUsdWithdraw);

    // Calculate for offchain purpose
    uint256 trsyPrice =
      totalSupply != 0 ? (1e18 * (_protocolAUM - totalUsdWithdraw)) / totalSupply : 0;
    emit Withdraw(_req.id, trsyPrice, totalUsdWithdraw, totalSharesToBurn);
    return totalUsdWithdraw;
  }

  function _govWithdraw(uint256 _protocolAUM, RequestData calldata _req)
    internal
    returns (uint256, uint256)
  {
    uint256 usdVal = getQuote(_req.assetOut[0], _req.amountOut[0]);

    if (usdVal == 0) revert AssetPriceNotAvailable();

    uint256 trsyToBurn = _convertToShares(usdVal, _protocolAUM);
    if (_req.slippageChecker < trsyToBurn) revert SlippageExceed();

    _burn(address(GOVERNANCE_MODULE), trsyToBurn);

    _decreaseAssetProxyAmount(_req.assetOut, _req.amountOut);

    GOVERNANCE_MODULE.govWithdraw(_req.requestor, _req.assetOut[0], _req.amountOut[0], trsyToBurn);
    IERC20(_req.assetOut[0]).safeTransfer(_req.requestor, _req.amountOut[0]);

    return (usdVal, trsyToBurn);
  }

  function _standardWithdraw(uint256 _protocolAUM, RequestData calldata _req)
    internal
    returns (uint256, uint256)
  {
    // check if requested token are available
    for (uint256 i = 0; i < _req.assetOut.length; i++) {
      if (standardAssetAccounting(_req.assetOut[i]) < _req.amountOut[i]) {
        revert FydeBalanceInsufficient();
      }
    }

    (, uint256 totalSharesToBurn,, uint256 taxInTRSY, uint256 totalUsdWithdraw) =
      getProcessParamWithdraw(_req, _protocolAUM);

    if (totalSharesToBurn > _req.slippageChecker) revert SlippageExceed();

    if (balanceOf[_req.requestor] < totalSharesToBurn) revert InsufficientTRSYBalance();

    _burn(_req.requestor, totalSharesToBurn);

    // Give tax to this contract
    if (taxInTRSY > 0) _mint(address(this), taxInTRSY);

    for (uint256 i = 0; i < _req.assetOut.length; i++) {
      // Send asset to recipient
      IERC20(_req.assetOut[i]).safeTransfer(_req.requestor, _req.amountOut[i]);
    }

    return (totalUsdWithdraw, totalSharesToBurn);
  }

  /*//////////////////////////////////////////////////////////////
                              SWAP
  //////////////////////////////////////////////////////////////*/

  function processSwap(uint256 _protocolAUM, RequestData calldata _req)
    external
    onlyRelayer
    returns (int256)
  {
    // Check if asset is supported
    _checkIsSupported(_req.assetIn);
    _checkIsSupported(_req.assetOut);
    _checkIsNotQuarantined(_req.assetIn);
    _checkIsNotQuarantined(_req.assetOut);
    _checkIfSwapAllowed(_req.assetIn);
    _checkIfSwapAllowed(_req.assetOut);

    // is keeper AUM in range
    (bool isInRange,) = _AumIsInRange(_protocolAUM);
    if (!isInRange) revert AumNotInRange();

    (uint256 amountOut, int256 deltaAUM) =
      getSwapAmountOut(_req.assetIn[0], _req.amountIn[0], _req.assetOut[0], _protocolAUM);
    if (amountOut == 0) revert SwapAmountNotAvailable();

    if (amountOut < _req.slippageChecker) revert SlippageExceed();

    // Check enough asset in protocol
    if (standardAssetAccounting(_req.assetOut[0]) < amountOut) revert FydeBalanceInsufficient();

    // Update AUM
    uint256 aum;
    // If the swapper pays net tax, we mint the corresponding TRSY to fyde. This way TRSY price
    // stays constant
    if (deltaAUM > 0) {
      aum = _protocolAUM + uint256(deltaAUM);
      _mint(address(this), _convertToShares(uint256(deltaAUM), _protocolAUM));
      // If incentives are higher tan taxes, we burn TRSY from fyde, to keep TRSY price constant
      // as backup if not enough TRSY in Fyde, we don't burn, i.e. TRSY price goes down and
      // incentives are
      // paid by pool
      // this way by frequently cashing out TRSY from fyde we can manually decide how much tax to
      // keep for ourselves
      // or leave in Fyde for incentives
    } else if (deltaAUM < 0) {
      aum = _protocolAUM - uint256(-deltaAUM);
      uint256 trsyToBurn = _convertToShares(uint256(-deltaAUM), _protocolAUM);
      trsyToBurn = balanceOf[address(this)] >= trsyToBurn ? trsyToBurn : balanceOf[address(this)];
      if (trsyToBurn != 0) _burn(address(this), trsyToBurn);
    } else {
      aum = _protocolAUM;
    }

    _updateProtocolAUM(aum);

    // Log accounting
    _increaseAssetTotalAmount(_req.assetIn[0], _req.amountIn[0]);
    _decreaseAssetTotalAmount(_req.assetOut[0], amountOut);

    // Transfer asset
    IERC20(_req.assetIn[0]).safeTransferFrom(_req.requestor, address(this), _req.amountIn[0]);
    IERC20(_req.assetOut[0]).safeTransfer(_req.requestor, amountOut);

    emit Swap(_req.id, _req.assetOut[0], amountOut);
    return deltaAUM;
  }

  /*///////////////////////////////////////////////////////////////
                              GETTERS
  //////////////////////////////////////////////////////////////*/

  ///@notice Give a quote for a speficic asset deposit
  ///@param _asset asset address to quote
  ///@param _amount amount of asset to deposit
  ///@return USD value of the specified deposit (return 18 decimals, 1USD = 1e18)
  ///@dev    If price is inconsistent or not available, returns 0 from oracle module -> needs proper
  ///        handling
  function getQuote(address _asset, uint256 _amount) public view override returns (uint256) {
    AssetInfo memory _assetInfo = assetInfo[_asset];
    uint256 price = oracleModule.getPriceInUSD(_asset, _assetInfo);
    return (_amount * price) / (10 ** _assetInfo.assetDecimals);
  }

  ///@notice Get the USD value of an asset in the protocol
  ///@param _asset asset address
  ///@return USD value of the asset
  ///@dev    If price is inconsistent or not available, returns 0 -> needs proper handling
  function getAssetAUM(address _asset) public view returns (uint256) {
    return getQuote(_asset, totalAssetAccounting[_asset]);
  }

  ///@notice Compute the USD AUM for the protocol
  ///@dev Should NOT be call within a contract (GAS EXPENSIVE), called off-chain by keeper
  function computeProtocolAUM() public view returns (uint256) {
    address asset;
    uint256 aum;
    uint256 assetAUM;
    address[] memory nAsset = assetsList;
    uint256 length = nAsset.length;
    for (uint256 i = 0; i < length; ++i) {
      asset = nAsset[i];
      if (totalAssetAccounting[asset] == 0) continue;
      assetAUM = getAssetAUM(asset);
      if (assetAUM == 0) return protocolData.aum;
      aum += assetAUM;
    }
    return aum;
  }

  /*//////////////////////////////////////////////////////////////
                        PROCESS PARAM
  //////////////////////////////////////////////////////////////*/

  ///@notice Return the process param for a deposit
  ///@param _req RequestData struct
  ///@param _protocolAUM AUM given by keeper
  ///@return processParam array of ProcessParam struct
  ///@return sharesToMint amount of shares to mint
  ///@return taxInTRSY amount of tax in TRSY
  ///@return totalUsdDeposit USD value of the depositn
  function getProcessParamDeposit(RequestData memory _req, uint256 _protocolAUM)
    public
    view
    returns (
      ProcessParam[] memory processParam,
      uint256 sharesToMint,
      uint256 taxInTRSY,
      uint256 totalUsdDeposit
    )
  {
    processParam = new ProcessParam[](_req.assetIn.length);

    // Build data struct and compute value of deposit
    for (uint256 i; i < _req.assetIn.length; i++) {
      uint256 usdVal = getQuote(_req.assetIn[i], _req.amountIn[i]);
      if (usdVal == 0) revert AssetPriceNotAvailable();

      processParam[i] = ProcessParam({
        targetConc: assetInfo[_req.assetIn[i]].targetConcentration,
        currentConc: _getAssetConcentration(_req.assetIn[i], _protocolAUM),
        usdValue: usdVal,
        sharesBeforeTax: _convertToShares(usdVal, _protocolAUM),
        taxableAmount: 0,
        taxInUSD: 0,
        sharesAfterTax: 0
      });

      totalUsdDeposit += usdVal;
    }

    for (uint256 i; i < processParam.length; i++) {
      // Get the TaxInUSD
      processParam[i] =
        _getDepositTax(processParam[i], _protocolAUM, totalUsdDeposit, protocolData.taxFactor);

      // Apply tax to the deposit
      processParam[i].sharesAfterTax =
        _convertToShares(processParam[i].usdValue - processParam[i].taxInUSD, _protocolAUM);
      sharesToMint += processParam[i].sharesAfterTax;
      taxInTRSY += processParam[i].sharesBeforeTax - processParam[i].sharesAfterTax;
    }

    return (processParam, sharesToMint, taxInTRSY, totalUsdDeposit);
  }

  ///@notice Return the process param for a withdraw
  ///@param _req RequestData struct
  ///@param _protocolAUM AUM given by keeper
  ///@return processParam array of ProcessParam struct
  ///@return totalSharesToBurn amount of shares to burn
  ///@return sharesToBurnBeforeTax amount of shares to burn before tax
  ///@return taxInTRSY amount of tax in TRSY
  ///@return totalUsdWithdraw USD value of the withdraw
  function getProcessParamWithdraw(RequestData calldata _req, uint256 _protocolAUM)
    public
    view
    returns (
      ProcessParam[] memory processParam,
      uint256 totalSharesToBurn,
      uint256 sharesToBurnBeforeTax,
      uint256 taxInTRSY,
      uint256 totalUsdWithdraw
    )
  {
    processParam = new ProcessParam[](_req.assetOut.length);

    // Build data struct and compute value of deposit
    for (uint256 i; i < _req.assetOut.length; i++) {
      uint256 usdVal = getQuote(_req.assetOut[i], _req.amountOut[i]);
      if (usdVal == 0) revert AssetPriceNotAvailable();

      processParam[i] = ProcessParam({
        targetConc: assetInfo[_req.assetOut[i]].targetConcentration,
        currentConc: _getAssetConcentration(_req.assetOut[i], _protocolAUM),
        usdValue: usdVal,
        sharesBeforeTax: 0,
        taxableAmount: 0,
        taxInUSD: 0,
        sharesAfterTax: 0
      });

      totalUsdWithdraw += usdVal;
    }

    for (uint256 i; i < processParam.length; i++) {
      // Get the TaxInUSD
      processParam[i] =
        _getWithdrawTax(processParam[i], _protocolAUM, totalUsdWithdraw, protocolData.taxFactor);
      taxInTRSY += _convertToShares(processParam[i].taxInUSD, _protocolAUM);
    }

    sharesToBurnBeforeTax = _convertToShares(totalUsdWithdraw, _protocolAUM);
    totalSharesToBurn = sharesToBurnBeforeTax + taxInTRSY;
  }

  ///@notice Return the amountOut for a swap accounting for tax and incentive
  ///@param _assetIn asset address to swap
  ///@param _amountIn amount of asset to swap
  ///@param _assetOut asset address to receive
  ///@param _protocolAUM AUM given by keeper
  function getSwapAmountOut(
    address _assetIn,
    uint256 _amountIn,
    address _assetOut,
    uint256 _protocolAUM
  ) public view returns (uint256, int256) {
    // Scope to avoid stack too deep
    {
      uint256 usdValIn = getQuote(_assetIn, _amountIn);
      uint256 assetOutPrice = getQuote(_assetOut, 10 ** assetInfo[_assetOut].assetDecimals);
      if (usdValIn == 0 || assetOutPrice == 0) return (0, int256(0));
    }

    ProcessParam memory processParamIn = ProcessParam({
      targetConc: assetInfo[_assetIn].targetConcentration,
      currentConc: _getAssetConcentration(_assetIn, _protocolAUM),
      usdValue: getQuote(_assetIn, _amountIn),
      sharesBeforeTax: 0,
      taxableAmount: 0,
      taxInUSD: 0,
      sharesAfterTax: 0
    });

    ProcessParam memory processParamOut = ProcessParam({
      targetConc: assetInfo[_assetOut].targetConcentration,
      currentConc: _getAssetConcentration(_assetOut, _protocolAUM),
      usdValue: 0,
      sharesBeforeTax: 0,
      taxableAmount: 0,
      taxInUSD: 0,
      sharesAfterTax: 0
    });

    uint256 usdAmountOut = _getSwapRate(
      processParamIn,
      processParamOut,
      _protocolAUM,
      protocolData.taxFactor,
      assetInfo[_assetIn].incentiveFactor,
      assetInfo[_assetOut].incentiveFactor
    );

    return (
      1e18 * usdAmountOut / getQuote(_assetOut, 1e18),
      int256(processParamIn.usdValue) - int256(usdAmountOut)
    );
  }

  /*//////////////////////////////////////////////////////////////
                            INTERNAL
  //////////////////////////////////////////////////////////////*/

  ///@notice Return asset concentration with keeper AUM
  ///@param _asset asset address
  ///@param _protocolAUM AUM given by keeper
  ///@return current concentration for an asset
  ///@dev    If price is inconsistent or not available, returns 0 -> needs proper handling
  function _getAssetConcentration(address _asset, uint256 _protocolAUM)
    internal
    view
    returns (uint256)
  {
    // To avoid division by 0
    if (_protocolAUM == 0 && protocolData.aum == 0) return 0;
    return (1e20 * getAssetAUM(_asset)) / _protocolAUM;
  }

  ///@notice Perform the comparison between AUM registry and one given by Keeper, return limited AUM
  /// if out of bounds
  function _AumIsInRange(uint256 _keeperAUM) internal view returns (bool, uint256) {
    uint16 maxAumDeviationAllowed = protocolData.maxAumDeviationAllowed;
    uint256 currAum = protocolData.aum;
    uint256 lowerBound = PercentageMath.percentSub(currAum, maxAumDeviationAllowed);
    uint256 upperBound = PercentageMath.percentAdd(currAum, maxAumDeviationAllowed);
    if (_keeperAUM < lowerBound) return (false, lowerBound);
    if (_keeperAUM > upperBound) return (false, upperBound);
    return (true, _keeperAUM);
  }

  function _checkIsSupported(address[] memory _assets) internal view {
    address notSupportedAsset = isAnyNotSupported(_assets);
    if (notSupportedAsset != address(0x0)) revert AssetNotSupported(notSupportedAsset);
  }

  function _checkIsNotQuarantined(address[] memory _assets) internal view {
    address quarantinedAsset = IRelayer(RELAYER).isAnyQuarantined(_assets);
    if (quarantinedAsset != address(0x0)) revert AssetIsQuarantined(quarantinedAsset);
  }

  function _checkIfSwapAllowed(address[] memory _assets) internal view {
    address notAllowedAsset = isSwapAllowed(_assets);
    if (notAllowedAsset != address(0x0)) revert SwapDisabled(notAllowedAsset);
  }

  /*//////////////////////////////////////////////////////////////
                            MODIFIERS
  //////////////////////////////////////////////////////////////*/

  modifier onlyRelayer() {
    if (msg.sender != RELAYER) revert Unauthorized();
    _;
  }
}

File 2 of 36 : TRSY.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import {ERC20} from "solmate/tokens/ERC20.sol";

///@title TRSY contract
///@notice Handle the logic for minting and burning TRSY shares
abstract contract TRSY is ERC20 {
  /*//////////////////////////////////////////////////////////////
                                 CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

  constructor() ERC20("TRSY", "TRSY", 18) {}

  /*//////////////////////////////////////////////////////////////
                                 INTERNAL
    //////////////////////////////////////////////////////////////*/

  ///@notice Convert the value of deposit into share of the protocol
  ///@param _usdValue usd value of the deposit
  ///@param _usdAUM AUM of the protocol in USD (given by keeper)
  ///@return TSRY share for an USD deposit
  function _convertToShares(uint256 _usdValue, uint256 _usdAUM) internal view returns (uint256) {
    uint256 supply = totalSupply;
    return supply == 0 ? _usdValue : (_usdValue * supply) / _usdAUM;
  }
}

File 3 of 36 : AssetRegistry.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import {AssetInfo} from "./Structs.sol";
import {AddressRegistry} from "./AddressRegistry.sol";
import {ProtocolState} from "./ProtocolState.sol";
import {Ownable} from "../utils/Ownable.sol";
import {BaseChecker} from "../utils/BaseChecker.sol";
import {IERC20Metadata} from "openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IUniswapV3PoolImmutables} from
  "lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol";

import {IRelayer} from "src/interfaces/IRelayer.sol";

///@title AssetRegistry contract
///@notice Handle logic and state for logging informations regarding the assets
abstract contract AssetRegistry is Ownable, BaseChecker, AddressRegistry, ProtocolState {
  /*//////////////////////////////////////////////////////////////
                                 STORAGE
    //////////////////////////////////////////////////////////////*/

  ///@notice Asset list;
  address[] public assetsList;

  ///@notice last block incentiveFactor was updated, safety measure
  uint128 public lastIncentiveUpdateBlock;
  int128 public incentiveCap;

  ///@notice Map asset address to struct containing info
  mapping(address => AssetInfo) public assetInfo;

  /*//////////////////////////////////////////////////////////////
                                 ERROR
    //////////////////////////////////////////////////////////////*/

  error PoolNotValid();
  error AssetSupported(address asset);
  error NotNormalized();
  error NotZero();
  error CoolDownPeriodActive();

  /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

  event AssetAdded(address _asset);
  event IncentiveFactorUpdated(address indexed asset, int72 incentiveFactor);
  event TargetConcentrationsUpdated();
  event UniswapPoolUpdated(address indexed asset, address uniswapPool);
  event AssetRemoved(address indexed asset);

  /*//////////////////////////////////////////////////////////////
                                 ADD ASSETS
    //////////////////////////////////////////////////////////////*/

  ///@notice Add assets in batch
  ///@param _assets Array of assets to add
  ///@param _uniswapPools Array of address of uniswap Pool
  ///@dev   only uniswap pool and incentive factor are relevant in assetsInfo, the rest is retrieved
  /// on-chain
  function addAssets(address[] calldata _assets, address[] calldata _uniswapPools)
    external
    onlyOwner
  {
    if (_assets.length != _uniswapPools.length) revert InconsistentLengths();

    for (uint256 i; i < _assets.length; ++i) {
      _addAsset(_assets[i], _uniswapPools[i]);
    }
  }

  function _addAsset(address _asset, address _uniswapPool) private {
    if (assetInfo[_asset].isSupported) revert AssetSupported(_asset);

    assetInfo[_asset].isSupported = true;
    assetInfo[_asset].assetDecimals = IERC20Metadata(_asset).decimals();

    setUniswapPool(_asset, _uniswapPool);

    assetsList.push(_asset);

    emit AssetAdded(_asset);
  }

  ///@notice Removes asset from the protocol whitelist
  ///@param _assetIdx index of the asset in the assets array
  ///@dev only possible if there are no tokens of the asset held by the protocol anymore
  function removeAsset(uint256 _assetIdx) external onlyOwner {
    address asset = assetsList[_assetIdx];
    if (totalAssetAccounting[asset] != 0) revert NotZero();
    if (assetInfo[asset].targetConcentration != 0) revert NotZero();
    delete assetInfo[asset];
    assetsList[_assetIdx] = assetsList[assetsList.length - 1];
    assetsList.pop();
    emit AssetRemoved(asset);
  }
  /*//////////////////////////////////////////////////////////////
                                 SETTER
    //////////////////////////////////////////////////////////////*/

  ///@notice Set target concentration for all asset
  ///@param _targetConcentrations Target concentration (1e18 -> 1%)
  ///@dev 1e18 = 1%
  ///@dev targetConcentrations must have same length as assetsList -> can only update all conc at
  // once to enforce normalization
  function setTargetConcentrations(uint72[] calldata _targetConcentrations) external onlyOwner {
    if (_targetConcentrations.length != assetsList.length) revert InconsistentLengths();
    uint72 sum;
    for (uint256 i; i < _targetConcentrations.length; i++) {
      sum += _targetConcentrations[i];
    }
    if (sum > (1e20 + 1e10) || sum < (1e20 - 1e10)) revert NotNormalized();

    for (uint256 i; i < _targetConcentrations.length; i++) {
      assetInfo[assetsList[i]].targetConcentration = _targetConcentrations[i];
    }
    emit TargetConcentrationsUpdated();
  }

  ///@notice Set target concentration for an asset
  ///@param _asset Asset address
  ///@param _incentiveFactor IncentiveFactor (1e18 -> 1%)
  ///@dev 1e18 = 1%, max incentiveCap
  ///@dev Can only be called every 5 blocks, safety measure in case of compromised IncentiveManager
  function setIncentiveFactor(address _asset, int72 _incentiveFactor) external onlyIncentiveManager {
    if (int128(_incentiveFactor) > incentiveCap) revert ValueOutOfBounds();
    if (block.number < uint256(lastIncentiveUpdateBlock) + 5) revert CoolDownPeriodActive();
    lastIncentiveUpdateBlock = uint128(block.number);
    assetInfo[_asset].incentiveFactor = _incentiveFactor;
    emit IncentiveFactorUpdated(_asset, _incentiveFactor);
  }

  ///@notice Set maximum incentive factor
  ///@param _incentiveCap maximum incentive factor
  ///@dev Capped at 1e20 == 100%
  function setIncentiveCap(int128 _incentiveCap) external onlyOwner {
    if (_incentiveCap > 1e20) revert ValueOutOfBounds();
    incentiveCap = _incentiveCap;
  }

  ///@notice Set uniswap pool for an asset
  ///@param _asset Asset address
  ///@param _uniswapPool Uniswap pool address
  function setUniswapPool(address _asset, address _uniswapPool) public onlyOwner {
    if (_uniswapPool == address(0x0)) {
      assetInfo[_asset].uniswapPool = _uniswapPool;
    } else {
      address token0 = IUniswapV3PoolImmutables(_uniswapPool).token0();
      address token1 = IUniswapV3PoolImmutables(_uniswapPool).token1();
      address quoteToken;

      if (token0 == _asset) quoteToken = token1;
      else if (token1 == _asset) quoteToken = token0;
      else revert PoolNotValid();

      assetInfo[_asset].uniswapPool = _uniswapPool;
      assetInfo[_asset].uniswapQuoteToken = quoteToken;
      assetInfo[_asset].quoteTokenDecimals = IERC20Metadata(quoteToken).decimals();
    }
    emit UniswapPoolUpdated(_asset, _uniswapPool);
  }

  /*//////////////////////////////////////////////////////////////
                                GETTER
    //////////////////////////////////////////////////////////////*/

  ///@notice Get isSupported for an asset
  ///@param _assets asset addresses
  ///@return address of first not supported asset or address(0x0) if all supported
  function isAnyNotSupported(address[] memory _assets) public view returns (address) {
    for (uint256 i; i < _assets.length; i++) {
      if (!assetInfo[_assets[i]].isSupported) return _assets[i];
    }
    return address(0x0);
  }

  ///@notice Get isSwapAllowed for an asset array
  ///@param _assets asset addresses
  ///@return address of first not supported asset or address(0x0) if all supported
  function isSwapAllowed(address[] memory _assets) public view returns (address) {
    for (uint256 i; i < _assets.length; i++) {
      if (assetInfo[_assets[i]].incentiveFactor == -100e18) return _assets[i];
    }
    return address(0x0);
  }

  ///@notice Get number of asset decimals
  ///@param _asset Asset address
  ///@return number of decimals
  function getAssetDecimals(address _asset) external view returns (uint8) {
    return assetInfo[_asset].assetDecimals;
  }

  ///@notice Get number of assets in protocol
  function getAssetsListLength() public view returns (uint256) {
    return assetsList.length;
  }

  ///@dev caller has to be whitelisted manager on relayer
  modifier onlyIncentiveManager() {
    if (!IRelayer(RELAYER).isIncentiveManager(msg.sender)) revert Unauthorized();
    _;
  }
}

File 4 of 36 : AddressRegistry.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

// Utils
import {Ownable} from "../utils/Ownable.sol";

// Interfaces
import {IOracle} from "../interfaces/IOracle.sol";
import {IGovernanceModule} from "../interfaces/IGovernanceModule.sol";

///@title AddressRegistry contract
///@notice Handle state and logic for external authorized call (mainly keeper) and the oracle module
abstract contract AddressRegistry is Ownable {
  /*//////////////////////////////////////////////////////////////
                            STORAGE
  //////////////////////////////////////////////////////////////*/

  ///@notice Address of the oracle module
  IOracle public oracleModule;

  ///@notice Governance Registry contract address interface
  IGovernanceModule public immutable GOVERNANCE_MODULE;

  address public RELAYER;

  /*//////////////////////////////////////////////////////////////
                            EVENTS
  //////////////////////////////////////////////////////////////*/

  event OracleModuleUpdated(address indexed oracleModule);

  /*//////////////////////////////////////////////////////////////
                        CONSTRUCTOR
  //////////////////////////////////////////////////////////////*/

  constructor(address _govModule, address _relayer) {
    GOVERNANCE_MODULE = IGovernanceModule(_govModule);
    RELAYER = _relayer;
  }

  /*//////////////////////////////////////////////////////////////
                            ACCESS
  //////////////////////////////////////////////////////////////*/

  function setRelayer(address _relayer) external onlyOwner {
    RELAYER = _relayer;
  }

  ///@notice Set the oracle address
  function setOracleModule(address _oracle) public onlyOwner {
    oracleModule = IOracle(_oracle);
    emit OracleModuleUpdated(_oracle);
  }
}

File 5 of 36 : ProtocolState.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import {ProtocolData} from "./Structs.sol";
import {Ownable} from "../utils/Ownable.sol";

///@title ProtocolState contract
///@notice Protocol data storage
abstract contract ProtocolState is Ownable {
  /*//////////////////////////////////////////////////////////////
                                 STORAGE
    //////////////////////////////////////////////////////////////*/

  ///@notice Protocol data
  ProtocolData public protocolData;

  ///@notice Number of token in the protocol
  mapping(address => uint256) public totalAssetAccounting;

  ///@notice Number of token in the proxy
  mapping(address => uint256) public proxyAssetAccounting;

  /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

  error ValueOutOfBounds();

  /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

  event ProtocolAumUpdated(uint256);
  event MaxAumDeviationAllowedUpdated(uint16);
  event TaxFactorUpdated(uint72);
  event ManagementFeeUpdated(uint72);

  /*//////////////////////////////////////////////////////////////
                                 GETTER
    //////////////////////////////////////////////////////////////*/

  ///@notice Get number of token in the standard pool
  ///@param _asset asset address
  ///@return number of token in standard pool
  function standardAssetAccounting(address _asset) public view returns (uint256) {
    return totalAssetAccounting[_asset] - proxyAssetAccounting[_asset];
  }

  ///@notice Get protocolAUM in USD
  ///@return protocol AUM
  function getProtocolAUM() external view returns (uint256) {
    return protocolData.aum;
  }

  /*//////////////////////////////////////////////////////////////
                                 SETTER
    //////////////////////////////////////////////////////////////*/

  ///@notice Change the AUM's comparison deviation threshold
  ///@param threshold new threshold
  ///@dev 200 = 2 % of deviation
  function updateMaxAumDeviationAllowed(uint16 threshold) public onlyOwner {
    // We bound the threshold to 0.1 % to 5%
    if (threshold < 10 || threshold > 500) revert ValueOutOfBounds();
    protocolData.maxAumDeviationAllowed = threshold;
    emit MaxAumDeviationAllowedUpdated(threshold);
  }

  ///@notice set the tax factor
  ///@param _taxFactor new tax factor
  ///@dev 100% = 100e18
  function updateTaxFactor(uint72 _taxFactor) public onlyOwner {
    if (_taxFactor > 100e18) revert ValueOutOfBounds();
    protocolData.taxFactor = _taxFactor;
    emit TaxFactorUpdated(_taxFactor);
  }

  ///@notice change annual management fee
  ///@param _annualFee new annual fee
  ///@dev 100% = 1e18
  function updateManagementFee(uint72 _annualFee) public onlyOwner {
    // We bound the fee to 0 % to 5%
    if (_annualFee > 5e16) revert ValueOutOfBounds();
    protocolData.managementFee = _annualFee;
    emit ManagementFeeUpdated(_annualFee);
  }

  ///@notice Update last fee collection time to current timestamp
  function _updateLastFeeCollectionTime() internal {
    protocolData.lastFeeCollectionTime = uint48(block.timestamp);
  }

  ///@notice Update the protocol AUM
  function _updateProtocolAUM(uint256 _aum) internal {
    protocolData.aum = _aum;
    emit ProtocolAumUpdated(_aum);
  }

  function _increaseAssetTotalAmount(address[] memory _assets, uint256[] memory _amounts) internal {
    for (uint256 i; i < _assets.length; i++) {
      _increaseAssetTotalAmount(_assets[i], _amounts[i]);
    }
  }

  function _increaseAssetTotalAmount(address _asset, uint256 _amount) internal {
    totalAssetAccounting[_asset] += _amount;
  }

  function _increaseAssetProxyAmount(address[] memory _assets, uint256[] memory _amounts) internal {
    for (uint256 i; i < _assets.length; i++) {
      proxyAssetAccounting[_assets[i]] += _amounts[i];
    }
  }

  function _decreaseAssetTotalAmount(address[] memory _assets, uint256[] memory _amounts) internal {
    for (uint256 i; i < _assets.length; i++) {
      _decreaseAssetTotalAmount(_assets[i], _amounts[i]);
    }
  }

  function _decreaseAssetTotalAmount(address _asset, uint256 _amount) internal {
    totalAssetAccounting[_asset] -= _amount;
  }

  function _decreaseAssetProxyAmount(address[] memory _assets, uint256[] memory _amounts) internal {
    for (uint256 i; i < _assets.length; i++) {
      proxyAssetAccounting[_assets[i]] -= _amounts[i];
    }
  }
}

File 6 of 36 : Tax.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import {ProcessParam} from "./Structs.sol";
import {MathUtil} from "../utils/MathUtil.sol";
import "synthetix-v3/utils/core-contracts/contracts/utils/SafeCast.sol";

///@title Tax contract
///@notice Handle tax logic, for either a deposit or withdraw compute if the action is unabalacing
/// the protocol
///        if this is the case, the protocol will compute a tax applied on deposit or withdraw by
/// reducing the number of shares to mint
///        or by increasing the number of shares to burn. This tax is then minted to fyde contract.
/// The main logic is that for each action, we compute a taxable amount which is the amount that
/// unbalance the protocol for a given deposit or withdraw,
/// then we apply the tax on this taxable amount.
/// For the swap the logic is the same, we compute the tax and incentive for assetIn and that give
/// the value of assetOut,
/// for this value we compute the tax and incentive for assetOut.
/// SwapRate can be greater for assetOut in case there is no tax and some incentives, the same if no
/// tax no incentive, or lower if there is tax and no incentive.
abstract contract Tax {
  using SafeCastU256 for uint256;
  using SafeCastI256 for int256;

  /*//////////////////////////////////////////////////////////////
                                 MAIN
    //////////////////////////////////////////////////////////////*/

  function _getDepositTax(
    ProcessParam memory processParam,
    uint256 protocolAUM,
    uint256 totalUsdDeposit,
    uint256 taxFactor
  ) internal pure returns (ProcessParam memory) {
    if (processParam.targetConc == 0) {
      processParam.taxInUSD = processParam.usdValue;
      return processParam;
    }
    if (taxFactor == 0) return processParam;
    processParam = _computeDepositTaxableAmount(processParam, protocolAUM, totalUsdDeposit);
    if (processParam.taxableAmount == 0) return processParam;
    processParam = _computeDepositTaxInUSD(processParam, protocolAUM, totalUsdDeposit, taxFactor);
    return processParam;
  }

  function _getWithdrawTax(
    ProcessParam memory processParam,
    uint256 protocolAUM,
    uint256 totalUsdWithdraw,
    uint256 taxFactor
  ) internal pure returns (ProcessParam memory) {
    if (taxFactor == 0) return processParam;
    processParam = _computeWithdrawTaxableAmount(processParam, protocolAUM, totalUsdWithdraw);
    if (processParam.taxableAmount == 0) return processParam;
    processParam = _computeWithdrawTaxInUSD(processParam, protocolAUM, totalUsdWithdraw, taxFactor);
    return processParam;
  }

  function _getSwapRate(
    ProcessParam memory processParamIn,
    ProcessParam memory processParamOut,
    uint256 protocolAUM,
    uint256 taxFactor,
    int256 incentiveFactorIn,
    int256 incentiveFactorOut
  ) internal pure returns (uint256) {
    // Compute tax on deposit
    processParamIn = _getDepositTax(processParamIn, protocolAUM, 0, taxFactor);

    int256 valIn = incentiveFactorIn
      * int256(processParamIn.usdValue - processParamIn.taxableAmount) / int256(1e20);

    // usdValue adjusted with potential tax and incentive
    uint256 withdrawValOut = valIn >= 0
      ? processParamIn.usdValue - processParamIn.taxInUSD + valIn.toUint()
      : processParamIn.usdValue - processParamIn.taxInUSD - (-1 * valIn).toUint();

    processParamOut.usdValue = withdrawValOut;
    processParamOut = _getWithdrawTax(processParamOut, protocolAUM, 0, taxFactor);

    // usdValueOut adjusted with potential tax and incentive
    int256 valOut =
      incentiveFactorOut * int256(withdrawValOut - processParamOut.taxableAmount) / 1e20;

    uint256 usdValOut = valOut >= 0
      ? withdrawValOut - processParamOut.taxInUSD + valOut.toUint()
      : withdrawValOut - processParamOut.taxInUSD - (-1 * valOut).toUint();

    return usdValOut;
  }

  /*//////////////////////////////////////////////////////////////
                                 DEPOSIT
    //////////////////////////////////////////////////////////////*/
  function _computeDepositTaxableAmount(
    ProcessParam memory processParam,
    uint256 protocolAUM,
    uint256 totalUsdDeposit
  ) internal pure returns (ProcessParam memory) {
    int256 deltaConc = protocolAUM.toInt()
      * (processParam.currentConc.toInt() - processParam.targetConc.toInt()) / 1e20;
    int256 targetDeposit = totalUsdDeposit != 0
      ? processParam.targetConc.toInt() * totalUsdDeposit.toInt() / 1e20
      : int256(0);
    int256 tax = processParam.usdValue.toInt() + deltaConc - targetDeposit;
    processParam.taxableAmount =
      MathUtil.min(processParam.usdValue.toInt(), MathUtil.max(tax, int256(0))).toUint();
    return processParam;
  }

  function _computeDepositTaxInUSD(
    ProcessParam memory processParam,
    uint256 protocolAUM,
    uint256 totalUsdDeposit,
    uint256 taxFactor
  ) internal pure returns (ProcessParam memory) {
    uint256 numerator = (protocolAUM * processParam.currentConc / 1e20) + processParam.usdValue;
    uint256 denominator = (protocolAUM + totalUsdDeposit) * processParam.targetConc / 1e20;
    uint256 eq = (1e18 * numerator / denominator) - 1e18;
    uint256 tmpRes = MathUtil.min(eq, 1e18);
    uint256 taxPerc = taxFactor * tmpRes / 1e20; // 1e20 for applying expressing tax as a percentage
    processParam.taxInUSD = processParam.taxableAmount * taxPerc / 1e18;
    return processParam;
  }

  /*//////////////////////////////////////////////////////////////
                                 WITHDRAW
    //////////////////////////////////////////////////////////////*/
  function _computeWithdrawTaxableAmount(
    ProcessParam memory processParam,
    uint256 protocolAUM,
    uint256 totalUsdWithdraw
  ) internal pure returns (ProcessParam memory) {
    int256 deltaConc = protocolAUM.toInt()
      * (processParam.currentConc.toInt() - processParam.targetConc.toInt()) / 1e20;
    int256 targetDeposit = processParam.targetConc.toInt() * totalUsdWithdraw.toInt() / 1e20;
    int256 tax = processParam.usdValue.toInt() - deltaConc - targetDeposit;
    processParam.taxableAmount =
      MathUtil.min(processParam.usdValue.toInt(), MathUtil.max(tax, int256(0))).toUint();
    return processParam;
  }

  function _computeWithdrawTaxInUSD(
    ProcessParam memory processParam,
    uint256 protocolAUM,
    uint256 totalUsdWithdraw,
    uint256 taxFactor
  ) internal pure returns (ProcessParam memory) {
    int256 numerator =
      protocolAUM.toInt() * processParam.currentConc.toInt() / 1e20 - processParam.usdValue.toInt();
    int256 denominator =
      processParam.targetConc.toInt() * (protocolAUM.toInt() - totalUsdWithdraw.toInt()) / 1e20;
    int256 tmpRes = 1e18 - (1e18 * numerator / denominator);
    uint256 tmpRes2 = MathUtil.min(tmpRes.toUint(), 1e18);
    uint256 taxPerc = taxFactor * tmpRes2 / 1e20; // 1e20 for applying expressing tax as a
      // percentage
    processParam.taxInUSD = processParam.taxableAmount * taxPerc / 1e18;
    return processParam;
  }
}

File 7 of 36 : GovernanceAccess.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

/// Import from Core /////
import {AddressRegistry} from "./AddressRegistry.sol";
import {AssetRegistry} from "./AssetRegistry.sol";
import {ProtocolState} from "./ProtocolState.sol";
import {TRSY} from "./TRSY.sol";

/// Structs /////
import {RebalanceParam} from "./Structs.sol";

// Interface
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";

///@title GovernanceAccess contract
///@notice Exposes functions for the governance module
abstract contract GovernanceAccess is TRSY, AddressRegistry, ProtocolState, AssetRegistry {
  using SafeERC20 for IERC20;

  ///@notice Called by the governance module in order to transfer asset when proxy is funded
  ///@param _asset asset address
  ///@param _recipient user address
  ///@param _amount number of token
  function transferAsset(address _asset, address _recipient, uint256 _amount)
    external
    onlyGovernance
  {
    IERC20(_asset).safeTransfer(_recipient, _amount);
  }

  ///@notice Called by the governance module in order to update proxy Accounting after rebalancing
  ///@param _asset asset address
  ///@param _amount number of token
  function updateAssetProxyAmount(address _asset, uint256 _amount) external onlyGovernance {
    proxyAssetAccounting[_asset] = _amount;
  }

  ///@notice Called by the governance module in order get all variables for rebalancing in one call
  /// (save gas)
  ///@param _asset asset address
  ///@return RebalanceParam struct with rebalance parameters
  function getRebalanceParams(address _asset) external view returns (RebalanceParam memory) {
    return RebalanceParam(
      _asset,
      totalAssetAccounting[_asset],
      proxyAssetAccounting[_asset],
      getQuote(_asset, 1e18),
      0,
      1e18 * protocolData.aum / totalSupply
    );
  }

  function getQuote(address _asset, uint256 _amount) public view virtual returns (uint256);

  modifier onlyGovernance() {
    if (msg.sender != address(GOVERNANCE_MODULE)) revert Unauthorized();
    _;
  }
}

File 8 of 36 : Structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

struct AssetInfo {
  uint72 targetConcentration;
  address uniswapPool;
  int72 incentiveFactor;
  uint8 assetDecimals;
  uint8 quoteTokenDecimals;
  address uniswapQuoteToken;
  bool isSupported;
}

struct ProtocolData {
  ///@notice Protocol AUM in USD
  uint256 aum;
  ///@notice multiplicator for the tax equation, 100% = 100e18
  uint72 taxFactor;
  ///@notice Max deviation allowed between AUM from keeper and registry
  uint16 maxAumDeviationAllowed; // Default val 200 == 2 %
  ///@notice block number where AUM was last updated
  uint48 lastAUMUpdateBlock;
  ///@notice annual fee on AUM, in % per year 100% = 100e18
  uint72 managementFee;
  ///@notice last block.timestamp when fee was collected
  uint48 lastFeeCollectionTime;
}

struct UserRequest {
  address asset;
  uint256 amount;
}

struct RequestData {
  uint32 id;
  address requestor;
  address[] assetIn;
  uint256[] amountIn;
  address[] assetOut;
  uint256[] amountOut;
  bool keepGovRights;
  uint256 slippageChecker;
}

struct RequestQ {
  uint64 start;
  uint64 end;
  mapping(uint64 => RequestData) requestData;
}

struct ProcessParam {
  uint256 targetConc;
  uint256 currentConc;
  uint256 usdValue;
  uint256 taxableAmount;
  uint256 taxInUSD;
  uint256 sharesBeforeTax;
  uint256 sharesAfterTax;
}

struct RebalanceParam {
  address asset;
  uint256 assetTotalAmount;
  uint256 assetProxyAmount;
  uint256 assetPrice;
  uint256 sTrsyTotalSupply;
  uint256 trsyPrice;
}

File 9 of 36 : Ownable.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

///@title Ownable contract
/// @notice Simple 2step owner authorization combining solmate and OZ implementation
abstract contract Ownable {
  /*//////////////////////////////////////////////////////////////
                             STORAGE
    //////////////////////////////////////////////////////////////*/

  ///@notice Address of the owner
  address public owner;

  ///@notice Address of the pending owner
  address public pendingOwner;

  /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

  event OwnershipTransferred(address indexed user, address indexed newOner);
  event OwnershipTransferStarted(address indexed user, address indexed newOwner);
  event OwnershipTransferCanceled(address indexed pendingOwner);

  /*//////////////////////////////////////////////////////////////
                                 ERROR
    //////////////////////////////////////////////////////////////*/

  error Unauthorized();

  /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

  constructor(address _owner) {
    owner = _owner;

    emit OwnershipTransferred(address(0), _owner);
  }

  /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

  ///@notice Transfer ownership to a new address
  ///@param newOwner address of the new owner
  ///@dev newOwner have to acceptOwnership
  function transferOwnership(address newOwner) external onlyOwner {
    pendingOwner = newOwner;
    emit OwnershipTransferStarted(msg.sender, pendingOwner);
  }

  ///@notice NewOwner accept the ownership, it transfer the ownership to newOwner
  function acceptOwnership() external {
    if (msg.sender != pendingOwner) revert Unauthorized();
    address oldOwner = owner;
    owner = pendingOwner;
    delete pendingOwner;
    emit OwnershipTransferred(oldOwner, owner);
  }

  ///@notice Cancel the ownership transfer
  function cancelTransferOwnership() external onlyOwner {
    emit OwnershipTransferCanceled(pendingOwner);
    delete pendingOwner;
  }

  modifier onlyOwner() {
    if (msg.sender != owner) revert Unauthorized();
    _;
  }
}

File 10 of 36 : PercentageMath.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

library PercentageMath {
  ///	CONSTANTS ///

  uint256 internal constant PERCENTAGE_FACTOR = 1e4; // 100.00%
  uint256 internal constant HALF_PERCENTAGE_FACTOR = 0.5e4; // 50.00%
  uint256 internal constant MAX_UINT256 = 2 ** 256 - 1;
  uint256 internal constant MAX_UINT256_MINUS_HALF_PERCENTAGE = 2 ** 256 - 1 - 0.5e4;

  /// INTERNAL ///

  ///@notice Check if value are within the range
  function _isInRange(uint256 valA, uint256 valB, uint256 deviationThreshold)
    internal
    pure
    returns (bool)
  {
    uint256 lowerBound = percentSub(valA, deviationThreshold);
    uint256 upperBound = percentAdd(valA, deviationThreshold);
    if (valB < lowerBound || valB > upperBound) return false;
    else return true;
  }

  /// @notice Executes a percentage addition (x * (1 + p)), rounded up.
  /// @param x The value to which to add the percentage.
  /// @param percentage The percentage of the value to add.
  /// @return y The result of the addition.
  function percentAdd(uint256 x, uint256 percentage) internal pure returns (uint256 y) {
    // Must revert if
    // PERCENTAGE_FACTOR + percentage > type(uint256).max
    //     or x * (PERCENTAGE_FACTOR + percentage) + HALF_PERCENTAGE_FACTOR > type(uint256).max
    // <=> percentage > type(uint256).max - PERCENTAGE_FACTOR
    //     or x > (type(uint256).max - HALF_PERCENTAGE_FACTOR) / (PERCENTAGE_FACTOR + percentage)
    // Note: PERCENTAGE_FACTOR + percentage >= PERCENTAGE_FACTOR > 0
    assembly {
      y := add(PERCENTAGE_FACTOR, percentage) // Temporary assignment to save gas.

      if or(
        gt(percentage, sub(MAX_UINT256, PERCENTAGE_FACTOR)),
        gt(x, div(MAX_UINT256_MINUS_HALF_PERCENTAGE, y))
      ) { revert(0, 0) }

      y := div(add(mul(x, y), HALF_PERCENTAGE_FACTOR), PERCENTAGE_FACTOR)
    }
  }

  /// @notice Executes a percentage subtraction (x * (1 - p)), rounded up.
  /// @param x The value to which to subtract the percentage.
  /// @param percentage The percentage of the value to subtract.
  /// @return y The result of the subtraction.
  function percentSub(uint256 x, uint256 percentage) internal pure returns (uint256 y) {
    // Must revert if
    // percentage > PERCENTAGE_FACTOR
    //     or x * (PERCENTAGE_FACTOR - percentage) + HALF_PERCENTAGE_FACTOR > type(uint256).max
    // <=> percentage > PERCENTAGE_FACTOR
    //     or ((PERCENTAGE_FACTOR - percentage) > 0 and x > (type(uint256).max -
    // HALF_PERCENTAGE_FACTOR) / (PERCENTAGE_FACTOR - percentage))
    assembly {
      y := sub(PERCENTAGE_FACTOR, percentage) // Temporary assignment to save gas.

      if or(
        gt(percentage, PERCENTAGE_FACTOR), mul(y, gt(x, div(MAX_UINT256_MINUS_HALF_PERCENTAGE, y)))
      ) { revert(0, 0) }

      y := div(add(mul(x, y), HALF_PERCENTAGE_FACTOR), PERCENTAGE_FACTOR)
    }
  }
}

File 11 of 36 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

File 12 of 36 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}

File 13 of 36 : IOracle.sol
//SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

import {AssetInfo} from "../core/Structs.sol";

interface IOracle {
  function getPriceInUSD(address, AssetInfo calldata) external view returns (uint256);

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

File 14 of 36 : IRelayer.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

import {RequestData, UserRequest} from "../core/Structs.sol";

interface IRelayer {
  function getNumPendingRequest() external view returns (uint256);

  function getRequest(uint64 idx) external view returns (RequestData memory);

  function requestGovernanceWithdraw(
    UserRequest memory _userRequest,
    address _user,
    uint256 _maxTRSYToPay
  ) external payable;

  function requestWithdraw(UserRequest[] memory _userRequest, uint256 _maxTRSYToPay)
    external
    payable;

  function requestDeposit(
    UserRequest[] memory _userRequest,
    bool _keepGovRights,
    uint256 _minTRSYExpected
  ) external payable;

  function requestSwap(
    address _assetIn,
    uint256 _amountIn,
    address _assetOut,
    uint256 _minAmountOut
  ) external payable;

  function processRequests(uint256 _protocolAUM) external;

  function isQuarantined(address _asset) external view returns (bool);

  function isIncentiveManager(address _incentiveManager) external view returns (bool);

  function MAX_ASSET_TO_REQUEST() external view returns (uint8);

  function actionToGasUsage(bytes32 _actionHash) external view returns (uint256);

  function isUser(address _asset) external view returns (bool);

  function isAnyQuarantined(address[] memory _assets) external view returns (address);
}

File 15 of 36 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

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

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

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 16 of 36 : BaseChecker.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

abstract contract BaseChecker {
  error ZeroParameter();
  error InconsistentLengths();

  function _checkZeroValue(uint256 val) internal pure {
    if (val == 0) revert ZeroParameter();
  }

  function _checkZeroAddress(address addr) internal pure {
    if (addr == address(0x0)) revert ZeroParameter();
  }

  function _checkForConsistentLength(address[] memory arr1, uint256[] memory arr2) internal pure {
    if (arr1.length != arr2.length) revert InconsistentLengths();
  }
}

File 17 of 36 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 18 of 36 : IUniswapV3PoolImmutables.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that never changes
/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values
interface IUniswapV3PoolImmutables {
    /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface
    /// @return The contract address
    function factory() external view returns (address);

    /// @notice The first of the two tokens of the pool, sorted by address
    /// @return The token contract address
    function token0() external view returns (address);

    /// @notice The second of the two tokens of the pool, sorted by address
    /// @return The token contract address
    function token1() external view returns (address);

    /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6
    /// @return The fee
    function fee() external view returns (uint24);

    /// @notice The pool tick spacing
    /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive
    /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...
    /// This value is an int24 to avoid casting even though it is always positive.
    /// @return The tick spacing
    function tickSpacing() external view returns (int24);

    /// @notice The maximum amount of position liquidity that can use any tick in the range
    /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
    /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
    /// @return The max amount of liquidity per tick
    function maxLiquidityPerTick() external view returns (uint128);
}

File 19 of 36 : IGovernanceModule.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;

interface IGovernanceModule {
  function fyde() external view returns (address);

  function proxyImplementation() external view returns (address);

  function proxyBalance(address proxy, address asset) external view returns (uint256);

  function strsyBalance(address _user, address _govToken) external view returns (uint256 balance);

  function assetToStrsy(address _asset) external view returns (address);

  function userToProxy(address _user) external view returns (address);

  function proxyToUser(address _proxy) external view returns (address);

  function isOnGovernanceWhitelist(address _asset) external view returns (bool);

  function getAllGovUsers() external view returns (address[] memory);

  function isAnyNotOnGovWhitelist(address[] calldata _assets) external view returns (address);

  function getUserGTAllowance(uint256 _TRSYAmount, address _token) external view returns (uint256);

  function govDeposit(
    address _depositor,
    address[] calldata _govToken,
    uint256[] calldata _amount,
    uint256[] calldata _amountTRSY,
    uint256 _totalTRSY
  ) external returns (address proxy);

  function govWithdraw(
    address _user,
    address _asset,
    uint256 _amountToWithdraw,
    uint256 _trsyToBurn
  ) external;

  function onStrsyTransfer(address sender, address _recipient) external;

  function unstakeGov(uint256 _amount, address _asset) external;

  function rebalanceProxy(address _proxy, address _asset, address[] memory _usersToRebalance)
    external;
}

File 20 of 36 : MathUtil.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)

pragma solidity 0.8.19;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library MathUtil {
  /**
   * @dev Returns the largest of two numbers.
   */
  function max(int256 a, int256 b) internal pure returns (int256) {
    return a >= b ? a : b;
  }

  /**
   * @dev Returns the smallest of two numbers.
   */
  function min(int256 a, int256 b) internal pure returns (int256) {
    return a < b ? a : b;
  }

  /**
   * @dev Returns the smallest of two numbers.
   */
  function min(uint256 a, uint256 b) internal pure returns (uint256) {
    return a < b ? a : b;
  }
}

File 21 of 36 : SafeCast.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * Utilities that convert numeric types avoiding silent overflows.
 */
import "./SafeCast/SafeCastU32.sol";
import "./SafeCast/SafeCastI32.sol";
import "./SafeCast/SafeCastI24.sol";
import "./SafeCast/SafeCastU56.sol";
import "./SafeCast/SafeCastI56.sol";
import "./SafeCast/SafeCastU64.sol";
import "./SafeCast/SafeCastI128.sol";
import "./SafeCast/SafeCastI256.sol";
import "./SafeCast/SafeCastU128.sol";
import "./SafeCast/SafeCastU160.sol";
import "./SafeCast/SafeCastU256.sol";
import "./SafeCast/SafeCastAddress.sol";
import "./SafeCast/SafeCastBytes32.sol";

File 22 of 36 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 23 of 36 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 24 of 36 : SafeCastU32.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastU32 {
    error OverflowUint32ToInt32();

    function toInt(uint32 x) internal pure returns (int32) {
        // -------------------------------o=========>----------------------
        // ----------------------<========o========>x----------------------
        if (x > uint32(type(int32).max)) {
            revert OverflowUint32ToInt32();
        }

        return int32(x);
    }

    function to256(uint32 x) internal pure returns (uint256) {
        return uint256(x);
    }

    function to56(uint32 x) internal pure returns (uint56) {
        return uint56(x);
    }
}

File 25 of 36 : SafeCastI32.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastI32 {
    error OverflowInt32ToUint32();

    function toUint(int32 x) internal pure returns (uint32) {
        // ----------------------<========o========>----------------------
        // ----------------------xxxxxxxxxo=========>----------------------
        if (x < 0) {
            revert OverflowInt32ToUint32();
        }

        return uint32(x);
    }
}

File 26 of 36 : SafeCastI24.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastI24 {
    function to256(int24 x) internal pure returns (int256) {
        return int256(x);
    }
}

File 27 of 36 : SafeCastU56.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastU56 {
    error OverflowUint56ToInt56();

    function toInt(uint56 x) internal pure returns (int56) {
        // -------------------------------o=========>----------------------
        // ----------------------<========o========>x----------------------
        if (x > uint56(type(int56).max)) {
            revert OverflowUint56ToInt56();
        }

        return int56(x);
    }
}

File 28 of 36 : SafeCastI56.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastI56 {
    error OverflowInt56ToInt24();

    function to24(int56 x) internal pure returns (int24) {
        // ----------------------<========o========>-----------------------
        // ----------------------xxx<=====o=====>xxx-----------------------
        if (x < int(type(int24).min) || x > int(type(int24).max)) {
            revert OverflowInt56ToInt24();
        }

        return int24(x);
    }
}

File 29 of 36 : SafeCastU64.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastU64 {
    error OverflowUint64ToInt64();

    function toInt(uint64 x) internal pure returns (int64) {
        // -------------------------------o=========>----------------------
        // ----------------------<========o========>x----------------------
        if (x > uint64(type(int64).max)) {
            revert OverflowUint64ToInt64();
        }

        return int64(x);
    }
}

File 30 of 36 : SafeCastI128.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastI128 {
    error OverflowInt128ToUint128();
    error OverflowInt128ToInt32();

    function toUint(int128 x) internal pure returns (uint128) {
        // ----------------<==============o==============>-----------------
        // ----------------xxxxxxxxxxxxxxxo===============>----------------
        if (x < 0) {
            revert OverflowInt128ToUint128();
        }

        return uint128(x);
    }

    function to256(int128 x) internal pure returns (int256) {
        return int256(x);
    }

    function to32(int128 x) internal pure returns (int32) {
        // ----------------<==============o==============>-----------------
        // ----------------xxxxxxxxxxxx<==o==>xxxxxxxxxxxx-----------------
        if (x < int(type(int32).min) || x > int(type(int32).max)) {
            revert OverflowInt128ToInt32();
        }

        return int32(x);
    }

    function zero() internal pure returns (int128) {
        return int128(0);
    }
}

File 31 of 36 : SafeCastI256.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastI256 {
    error OverflowInt256ToUint256();
    error OverflowInt256ToInt128();
    error OverflowInt256ToInt24();

    function to128(int256 x) internal pure returns (int128) {
        // ----<==========================o===========================>----
        // ----xxxxxxxxxxxx<==============o==============>xxxxxxxxxxxxx----
        if (x < int256(type(int128).min) || x > int256(type(int128).max)) {
            revert OverflowInt256ToInt128();
        }

        return int128(x);
    }

    function to24(int256 x) internal pure returns (int24) {
        // ----<==========================o===========================>----
        // ----xxxxxxxxxxxxxxxxxxxx<======o=======>xxxxxxxxxxxxxxxxxxxx----
        if (x < int256(type(int24).min) || x > int256(type(int24).max)) {
            revert OverflowInt256ToInt24();
        }

        return int24(x);
    }

    function toUint(int256 x) internal pure returns (uint256) {
        // ----<==========================o===========================>----
        // ----xxxxxxxxxxxxxxxxxxxxxxxxxxxo===============================>
        if (x < 0) {
            revert OverflowInt256ToUint256();
        }

        return uint256(x);
    }

    function zero() internal pure returns (int256) {
        return int256(0);
    }
}

File 32 of 36 : SafeCastU128.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastU128 {
    error OverflowUint128ToInt128();

    function to256(uint128 x) internal pure returns (uint256) {
        return uint256(x);
    }

    function toInt(uint128 x) internal pure returns (int128) {
        // -------------------------------o===============>----------------
        // ----------------<==============o==============>x----------------
        if (x > uint128(type(int128).max)) {
            revert OverflowUint128ToInt128();
        }

        return int128(x);
    }

    function toBytes32(uint128 x) internal pure returns (bytes32) {
        return bytes32(uint256(x));
    }
}

File 33 of 36 : SafeCastU160.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastU160 {
    function to256(uint160 x) internal pure returns (uint256) {
        return uint256(x);
    }
}

File 34 of 36 : SafeCastU256.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastU256 {
    error OverflowUint256ToUint128();
    error OverflowUint256ToInt256();
    error OverflowUint256ToUint64();
    error OverflowUint256ToUint32();
    error OverflowUint256ToUint160();

    function to128(uint256 x) internal pure returns (uint128) {
        // -------------------------------o===============================>
        // -------------------------------o===============>xxxxxxxxxxxxxxxx
        if (x > type(uint128).max) {
            revert OverflowUint256ToUint128();
        }

        return uint128(x);
    }

    function to64(uint256 x) internal pure returns (uint64) {
        // -------------------------------o===============================>
        // -------------------------------o======>xxxxxxxxxxxxxxxxxxxxxxxxx
        if (x > type(uint64).max) {
            revert OverflowUint256ToUint64();
        }

        return uint64(x);
    }

    function to32(uint256 x) internal pure returns (uint32) {
        // -------------------------------o===============================>
        // -------------------------------o===>xxxxxxxxxxxxxxxxxxxxxxxxxxxx
        if (x > type(uint32).max) {
            revert OverflowUint256ToUint32();
        }

        return uint32(x);
    }

    function to160(uint256 x) internal pure returns (uint160) {
        // -------------------------------o===============================>
        // -------------------------------o==================>xxxxxxxxxxxxx
        if (x > type(uint160).max) {
            revert OverflowUint256ToUint160();
        }

        return uint160(x);
    }

    function toBytes32(uint256 x) internal pure returns (bytes32) {
        return bytes32(x);
    }

    function toInt(uint256 x) internal pure returns (int256) {
        // -------------------------------o===============================>
        // ----<==========================o===========================>xxxx
        if (x > uint256(type(int256).max)) {
            revert OverflowUint256ToInt256();
        }

        return int256(x);
    }
}

File 35 of 36 : SafeCastAddress.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastAddress {
    function toBytes32(address x) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(x)));
    }
}

File 36 of 36 : SafeCastBytes32.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.11 <0.9.0;

/**
 * @title See SafeCast.sol.
 */
library SafeCastBytes32 {
    function toAddress(bytes32 x) internal pure returns (address) {
        return address(uint160(uint256(x)));
    }

    function toUint(bytes32 x) internal pure returns (uint) {
        return uint(x);
    }
}

Settings
{
  "remappings": [
    "@uniswap/v3-core/=lib/v3-core/",
    "@uniswap/v3-periphery/=lib/v3-periphery/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "solmate/=lib/solmate/src/",
    "synthetix-v3/=lib/synthetix-v3/",
    "v3-core/=lib/v3-core/contracts/",
    "v3-periphery/=lib/v3-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_relayer","type":"address"},{"internalType":"address","name":"_oracleModule","type":"address"},{"internalType":"address","name":"_governanceModule","type":"address"},{"internalType":"uint16","name":"_maxAumDeviationAllowed","type":"uint16"},{"internalType":"uint72","name":"_taxFactor","type":"uint72"},{"internalType":"uint72","name":"_managementFee","type":"uint72"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"AssetIsQuarantined","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"AssetNotSupported","type":"error"},{"inputs":[],"name":"AssetPriceNotAvailable","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"AssetSupported","type":"error"},{"inputs":[],"name":"AumNotInRange","type":"error"},{"inputs":[],"name":"CoolDownPeriodActive","type":"error"},{"inputs":[],"name":"FydeBalanceInsufficient","type":"error"},{"inputs":[],"name":"InconsistentLengths","type":"error"},{"inputs":[],"name":"InsufficientTRSYBalance","type":"error"},{"inputs":[],"name":"NotNormalized","type":"error"},{"inputs":[],"name":"NotZero","type":"error"},{"inputs":[],"name":"OnlyOneUpdatePerBlock","type":"error"},{"inputs":[],"name":"OverflowInt256ToUint256","type":"error"},{"inputs":[],"name":"OverflowUint256ToInt256","type":"error"},{"inputs":[],"name":"PoolNotValid","type":"error"},{"inputs":[],"name":"SlippageExceed","type":"error"},{"inputs":[],"name":"SwapAmountNotAvailable","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"SwapDisabled","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ValueOutOfBounds","type":"error"},{"inputs":[],"name":"ZeroParameter","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_asset","type":"address"}],"name":"AssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"}],"name":"AssetRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"requestId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"trsyPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usdDepositValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"trsyMinted","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"trsyFeesCollected","type":"uint256"}],"name":"FeesCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"int72","name":"incentiveFactor","type":"int72"}],"name":"IncentiveFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feeToMint","type":"uint256"}],"name":"ManagementFeeCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint72","name":"","type":"uint72"}],"name":"ManagementFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"","type":"uint16"}],"name":"MaxAumDeviationAllowedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracleModule","type":"address"}],"name":"OracleModuleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipTransferCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"ProtocolAumUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"requestId","type":"uint32"},{"indexed":false,"internalType":"address","name":"assetOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[],"name":"TargetConcentrationsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint72","name":"","type":"uint72"}],"name":"TaxFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"uniswapPool","type":"address"}],"name":"UniswapPoolUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"requestId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"trsyPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usdWithdrawValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"trsyBurned","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNANCE_MODULE","outputs":[{"internalType":"contract IGovernanceModule","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"},{"internalType":"address[]","name":"_uniswapPools","type":"address[]"}],"name":"addAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetInfo","outputs":[{"internalType":"uint72","name":"targetConcentration","type":"uint72"},{"internalType":"address","name":"uniswapPool","type":"address"},{"internalType":"int72","name":"incentiveFactor","type":"int72"},{"internalType":"uint8","name":"assetDecimals","type":"uint8"},{"internalType":"uint8","name":"quoteTokenDecimals","type":"uint8"},{"internalType":"address","name":"uniswapQuoteToken","type":"address"},{"internalType":"bool","name":"isSupported","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"assetsList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelTransferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"collectFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collectManagementFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"computeProtocolAUM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAssetAUM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAssetDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAssetsListLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address","name":"requestor","type":"address"},{"internalType":"address[]","name":"assetIn","type":"address[]"},{"internalType":"uint256[]","name":"amountIn","type":"uint256[]"},{"internalType":"address[]","name":"assetOut","type":"address[]"},{"internalType":"uint256[]","name":"amountOut","type":"uint256[]"},{"internalType":"bool","name":"keepGovRights","type":"bool"},{"internalType":"uint256","name":"slippageChecker","type":"uint256"}],"internalType":"struct RequestData","name":"_req","type":"tuple"},{"internalType":"uint256","name":"_protocolAUM","type":"uint256"}],"name":"getProcessParamDeposit","outputs":[{"components":[{"internalType":"uint256","name":"targetConc","type":"uint256"},{"internalType":"uint256","name":"currentConc","type":"uint256"},{"internalType":"uint256","name":"usdValue","type":"uint256"},{"internalType":"uint256","name":"taxableAmount","type":"uint256"},{"internalType":"uint256","name":"taxInUSD","type":"uint256"},{"internalType":"uint256","name":"sharesBeforeTax","type":"uint256"},{"internalType":"uint256","name":"sharesAfterTax","type":"uint256"}],"internalType":"struct ProcessParam[]","name":"processParam","type":"tuple[]"},{"internalType":"uint256","name":"sharesToMint","type":"uint256"},{"internalType":"uint256","name":"taxInTRSY","type":"uint256"},{"internalType":"uint256","name":"totalUsdDeposit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address","name":"requestor","type":"address"},{"internalType":"address[]","name":"assetIn","type":"address[]"},{"internalType":"uint256[]","name":"amountIn","type":"uint256[]"},{"internalType":"address[]","name":"assetOut","type":"address[]"},{"internalType":"uint256[]","name":"amountOut","type":"uint256[]"},{"internalType":"bool","name":"keepGovRights","type":"bool"},{"internalType":"uint256","name":"slippageChecker","type":"uint256"}],"internalType":"struct RequestData","name":"_req","type":"tuple"},{"internalType":"uint256","name":"_protocolAUM","type":"uint256"}],"name":"getProcessParamWithdraw","outputs":[{"components":[{"internalType":"uint256","name":"targetConc","type":"uint256"},{"internalType":"uint256","name":"currentConc","type":"uint256"},{"internalType":"uint256","name":"usdValue","type":"uint256"},{"internalType":"uint256","name":"taxableAmount","type":"uint256"},{"internalType":"uint256","name":"taxInUSD","type":"uint256"},{"internalType":"uint256","name":"sharesBeforeTax","type":"uint256"},{"internalType":"uint256","name":"sharesAfterTax","type":"uint256"}],"internalType":"struct ProcessParam[]","name":"processParam","type":"tuple[]"},{"internalType":"uint256","name":"totalSharesToBurn","type":"uint256"},{"internalType":"uint256","name":"sharesToBurnBeforeTax","type":"uint256"},{"internalType":"uint256","name":"taxInTRSY","type":"uint256"},{"internalType":"uint256","name":"totalUsdWithdraw","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProtocolAUM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getQuote","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getRebalanceParams","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"assetTotalAmount","type":"uint256"},{"internalType":"uint256","name":"assetProxyAmount","type":"uint256"},{"internalType":"uint256","name":"assetPrice","type":"uint256"},{"internalType":"uint256","name":"sTrsyTotalSupply","type":"uint256"},{"internalType":"uint256","name":"trsyPrice","type":"uint256"}],"internalType":"struct RebalanceParam","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_assetIn","type":"address"},{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"address","name":"_assetOut","type":"address"},{"internalType":"uint256","name":"_protocolAUM","type":"uint256"}],"name":"getSwapAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"incentiveCap","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"}],"name":"isAnyNotSupported","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_assets","type":"address[]"}],"name":"isSwapAllowed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastIncentiveUpdateBlock","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleModule","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_protocolAUM","type":"uint256"},{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address","name":"requestor","type":"address"},{"internalType":"address[]","name":"assetIn","type":"address[]"},{"internalType":"uint256[]","name":"amountIn","type":"uint256[]"},{"internalType":"address[]","name":"assetOut","type":"address[]"},{"internalType":"uint256[]","name":"amountOut","type":"uint256[]"},{"internalType":"bool","name":"keepGovRights","type":"bool"},{"internalType":"uint256","name":"slippageChecker","type":"uint256"}],"internalType":"struct RequestData","name":"_req","type":"tuple"}],"name":"processDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_protocolAUM","type":"uint256"},{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address","name":"requestor","type":"address"},{"internalType":"address[]","name":"assetIn","type":"address[]"},{"internalType":"uint256[]","name":"amountIn","type":"uint256[]"},{"internalType":"address[]","name":"assetOut","type":"address[]"},{"internalType":"uint256[]","name":"amountOut","type":"uint256[]"},{"internalType":"bool","name":"keepGovRights","type":"bool"},{"internalType":"uint256","name":"slippageChecker","type":"uint256"}],"internalType":"struct RequestData","name":"_req","type":"tuple"}],"name":"processSwap","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_protocolAUM","type":"uint256"},{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"address","name":"requestor","type":"address"},{"internalType":"address[]","name":"assetIn","type":"address[]"},{"internalType":"uint256[]","name":"amountIn","type":"uint256[]"},{"internalType":"address[]","name":"assetOut","type":"address[]"},{"internalType":"uint256[]","name":"amountOut","type":"uint256[]"},{"internalType":"bool","name":"keepGovRights","type":"bool"},{"internalType":"uint256","name":"slippageChecker","type":"uint256"}],"internalType":"struct RequestData","name":"_req","type":"tuple"}],"name":"processWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocolData","outputs":[{"internalType":"uint256","name":"aum","type":"uint256"},{"internalType":"uint72","name":"taxFactor","type":"uint72"},{"internalType":"uint16","name":"maxAumDeviationAllowed","type":"uint16"},{"internalType":"uint48","name":"lastAUMUpdateBlock","type":"uint48"},{"internalType":"uint72","name":"managementFee","type":"uint72"},{"internalType":"uint48","name":"lastFeeCollectionTime","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"proxyAssetAccounting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetIdx","type":"uint256"}],"name":"removeAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int128","name":"_incentiveCap","type":"int128"}],"name":"setIncentiveCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"int72","name":"_incentiveFactor","type":"int72"}],"name":"setIncentiveFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oracle","type":"address"}],"name":"setOracleModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_relayer","type":"address"}],"name":"setRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint72[]","name":"_targetConcentrations","type":"uint72[]"}],"name":"setTargetConcentrations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_uniswapPool","type":"address"}],"name":"setUniswapPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"standardAssetAccounting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalAssetAccounting","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"updateAssetProxyAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint72","name":"_annualFee","type":"uint72"}],"name":"updateManagementFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"threshold","type":"uint16"}],"name":"updateMaxAumDeviationAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_aum","type":"uint256"}],"name":"updateProtocolAUM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint72","name":"_taxFactor","type":"uint72"}],"name":"updateTaxFactor","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101006040523480156200001257600080fd5b506040516200660e3803806200660e83398101604081905262000035916200047a565b838633604051806040016040528060048152602001635452535960e01b815250604051806040016040528060048152602001635452535960e01b81525060128260009081620000859190620005a8565b506001620000948382620005a8565b5060ff81166080524660a052620000aa62000183565b60c0525050600680546001600160a01b0319166001600160a01b0384169081179091556040519091506000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b0391821660e052600980549183166001600160a01b031992831617905560088054928816929091169190911790556200013c836200021f565b6200014782620002df565b62000152816200038d565b62000177600b80546001600160d01b0316600160d01b4265ffffffffffff1602179055565b505050505050620006f2565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620001b7919062000674565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6006546001600160a01b031633146200024a576040516282b42960e81b815260040160405180910390fd5b600a8161ffff1610806200026357506101f48161ffff16115b156200028257604051636d4d4a6760e11b815260040160405180910390fd5b600b805461ffff60481b1916690100000000000000000061ffff8416908102919091179091556040519081527fd08c1bc3993b0af9ff782c23b664467f9c10136abbd2f03262557fc2abde0f55906020015b60405180910390a150565b6006546001600160a01b031633146200030a576040516282b42960e81b815260040160405180910390fd5b68056bc75e2d63100000816001600160481b031611156200033e57604051636d4d4a6760e11b815260040160405180910390fd5b600b80546001600160481b0319166001600160481b0383169081179091556040519081527ff036cc909a40e5a5297fc43a607fba898d621fe78a6153d56c6bf249ce92dee490602001620002d4565b6006546001600160a01b03163314620003b8576040516282b42960e81b815260040160405180910390fd5b66b1a2bc2ec50000816001600160481b03161115620003ea57604051636d4d4a6760e11b815260040160405180910390fd5b600b8054600160881b600160d01b031916600160881b6001600160481b038416908102919091179091556040519081527f40ecaade69bfd8d44b55fee3f7dc31cdb78157320c6ba966c032db84bd85586090602001620002d4565b80516001600160a01b03811681146200045d57600080fd5b919050565b80516001600160481b03811681146200045d57600080fd5b60008060008060008060c087890312156200049457600080fd5b6200049f8762000445565b9550620004af6020880162000445565b9450620004bf6040880162000445565b9350606087015161ffff81168114620004d757600080fd5b9250620004e76080880162000462565b9150620004f760a0880162000462565b90509295509295509295565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200052e57607f821691505b6020821081036200054f57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005a357600081815260208120601f850160051c810160208610156200057e5750805b601f850160051c820191505b818110156200059f578281556001016200058a565b5050505b505050565b81516001600160401b03811115620005c457620005c462000503565b620005dc81620005d5845462000519565b8462000555565b602080601f831160018114620006145760008415620005fb5750858301515b600019600386901b1c1916600185901b1785556200059f565b600085815260208120601f198616915b82811015620006455788860151825594840194600190910190840162000624565b5085821015620006645787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000808354620006848162000519565b600182811680156200069f5760018114620006b557620006e6565b60ff1984168752821515830287019450620006e6565b8760005260208060002060005b85811015620006dd5781548a820152908401908201620006c2565b50505082870194505b50929695505050505050565b60805160a05160c05160e051615eb86200075660003960008181610457015281816116500152818161191501528181613aa101528181613c8a0152818161439a015261444f01526000611623015260006115ee015260006104ef0152615eb86000f3fe608060405234801561001057600080fd5b50600436106103995760003560e01c806382c0ab21116101e9578063cc88688b1161010f578063e787caa4116100ad578063f2fde38b1161007c578063f2fde38b14610a0c578063f58f951014610a1f578063f6fabac614610a47578063fdc5a0fe14610a6757600080fd5b8063e787caa4146109c0578063eb95c56c146109d3578063ec2a0992146109e6578063f14f58f1146109f957600080fd5b8063db10e60f116100e9578063db10e60f1461095c578063dd62ed3e1461096f578063e02ff0541461099a578063e30c3978146109ad57600080fd5b8063cc88688b146108a2578063d505accf146108b5578063d7691f8f146108c857600080fd5b80639622c75611610187578063a9059cbb11610156578063a9059cbb14610806578063aeabb17f14610819578063b023c8651461082c578063c76ece881461088f57600080fd5b80639622c756146107915780639c016ffd146107b55780639efd6f72146107bd578063a033fcd4146107f357600080fd5b80638be859ec116101c35780638be859ec146107665780638da5cb5b1461076e57806392fede001461078157806395d89b411461078957600080fd5b806382c0ab211461068257806383307f43146106955780638b0dcb4e1461069d57600080fd5b80633745a192116102ce57806371e85c411161026c5780637bcbb1dd1161023b5780637bcbb1dd146106295780637d43447e1461063c5780637ebcf3bf1461064f5780637ecebe001461066257600080fd5b806371e85c41146105e85780637494e604146105fb57806379ba50971461060e5780637acab86e1461061657600080fd5b80636548e9bc116102a85780636548e9bc1461058f578063683ab4a9146105a25780636ede2988146105b557806370a08231146105c857600080fd5b80633745a1921461053e578063439e2e451461056957806352e49dd91461057c57600080fd5b806323b872dd1161033b5780632efda2bc116103155780632efda2bc146104ca578063313ce567146104ea57806335dda72f146105235780633644e5151461053657600080fd5b806323b872dd146104915780632483e715146104a45780632d58fd75146104b757600080fd5b8063095ea7b311610377578063095ea7b3146103f5578063154bb43c1461041857806318160ddd1461043b5780631a366bb71461045257600080fd5b806302e43cbc1461039e5780630505af94146103b357806306fdde03146103e0575b600080fd5b6103b16103ac366004614ffb565b610a6f565b005b600f80546103c891600160801b909104900b81565b604051600f9190910b81526020015b60405180910390f35b6103e8610b2d565b6040516103d79190615048565b6104086104033660046150a0565b610bbb565b60405190151581526020016103d7565b61042b610426366004615350565b610c28565b6040516103d7949392919061540d565b61044460025481565b6040519081526020016103d7565b6104797f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016103d7565b61040861049f36600461543c565b610f6d565b600954610479906001600160a01b031681565b6104446104c5366004615496565b61104d565b6104446104d83660046154dc565b600c6020526000908152604090205481565b6105117f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016103d7565b6103b16105313660046154f9565b611306565b6104446115ea565b600f54610551906001600160801b031681565b6040516001600160801b0390911681526020016103d7565b6103b161057736600461543c565b611645565b6103b161058a366004615532565b6116a6565b6103b161059d3660046154dc565b61175c565b6103b16105b036600461559a565b6117a8565b6103b16105c3366004615605565b61186a565b6104446105d63660046154dc565b60036020526000908152604090205481565b6104796105f6366004615628565b6118e0565b6103b16106093660046150a0565b61190a565b6103b161196e565b610444610624366004615496565b6119f5565b6103b1610637366004615641565b611eba565b61044461064a366004615496565b612039565b6103b161065d366004614ffb565b61221d565b6104446106703660046154dc565b60056020526000908152604090205481565b6104446106903660046150a0565b6122ca565b6104446123f6565b61070f6106ab3660046154dc565b601060205260009081526040902080546001909101546001600160481b038216916001600160a01b03600160481b91829004811692600881900b9260ff908204811692600160501b8304821692600160581b810490911691600160f81b9091041687565b604080516001600160481b0390981688526001600160a01b03968716602089015260089590950b9487019490945260ff9283166060870152911660808501529190911660a0830152151560c082015260e0016103d7565b600a54610444565b600654610479906001600160a01b031681565b6103b16124fd565b6103e8612571565b6107a461079f366004615676565b61257e565b6040516103d79594939291906156ab565b6103b1612850565b6105116107cb3660046154dc565b6001600160a01b0316600090815260106020526040902060010154600160481b900460ff1690565b6103b16108013660046150a0565b612941565b6104086108143660046150a0565b612a09565b6104796108273660046156e2565b612a6f565b61083f61083a3660046154dc565b612b09565b6040516103d7919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0918201519181019190915260c00190565b6103b161089d366004615716565b612bd9565b600854610479906001600160a01b031681565b6103b16108c3366004615766565b612d95565b600a54600b5461091291906001600160481b038082169161ffff600160481b8204169165ffffffffffff600160581b8304811692600160881b810490921691600160d01b90041686565b604080519687526001600160481b03958616602088015261ffff9094169386019390935265ffffffffffff91821660608601529290921660808401521660a082015260c0016103d7565b61047961096a3660046156e2565b612fde565b61044461097d3660046154f9565b600460209081526000928352604080842090915290825290205481565b6104446109a83660046154dc565b613062565b600754610479906001600160a01b031681565b6103b16109ce366004615628565b613090565b6104446109e13660046154dc565b613141565b6103b16109f43660046154dc565b613165565b6103b1610a07366004615628565b6131d9565b6103b1610a1a3660046154dc565b6133af565b610a32610a2d3660046157d7565b613425565b604080519283526020830191909152016103d7565b610444610a553660046154dc565b600d6020526000908152604090205481565b600e54610444565b6006546001600160a01b03163314610a99576040516282b42960e81b815260040160405180910390fd5b66b1a2bc2ec50000816001600160481b03161115610aca57604051636d4d4a6760e11b815260040160405180910390fd5b600b805468ffffffffffffffffff60881b1916600160881b6001600160481b038416908102919091179091556040519081527f40ecaade69bfd8d44b55fee3f7dc31cdb78157320c6ba966c032db84bd855860906020015b60405180910390a150565b60008054610b3a9061581f565b80601f0160208091040260200160405190810160405280929190818152602001828054610b669061581f565b8015610bb35780601f10610b8857610100808354040283529160200191610bb3565b820191906000526020600020905b815481529060010190602001808311610b9657829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610c169086815260200190565b60405180910390a35060015b92915050565b606060008060008560400151516001600160401b03811115610c4c57610c4c6150cc565b604051908082528060200260200182016040528015610c8557816020015b610c72614fbe565b815260200190600190039081610c6a5790505b50935060005b866040015151811015610e04576000610cde88604001518381518110610cb357610cb3615853565b602002602001015189606001518481518110610cd157610cd1615853565b60200260200101516122ca565b905080600003610d015760405163e49d3ed160e01b815260040160405180910390fd5b6040518060e00160405280601060008b604001518681518110610d2657610d26615853565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060000160009054906101000a90046001600160481b03166001600160481b03168152602001610d9a8a604001518581518110610d8c57610d8c615853565b60200260200101518a613601565b81526020018281526020016000815260200160008152602001610dbd838a61364c565b81526020016000815250868381518110610dd957610dd9615853565b6020908102919091010152610dee818461587f565b9250508080610dfc90615892565b915050610c8b565b5060005b8451811015610f6357610e46858281518110610e2657610e26615853565b6020908102919091010151600b54889085906001600160481b031661367c565b858281518110610e5857610e58615853565b6020026020010181905250610eb2858281518110610e7857610e78615853565b602002602001015160800151868381518110610e9657610e96615853565b602002602001015160400151610eac91906158ab565b8761364c565b858281518110610ec457610ec4615853565b602002602001015160c0018181525050848181518110610ee657610ee6615853565b602002602001015160c0015184610efd919061587f565b9350848181518110610f1157610f11615853565b602002602001015160c00151858281518110610f2f57610f2f615853565b602002602001015160a00151610f4591906158ab565b610f4f908461587f565b925080610f5b81615892565b915050610e08565b5092959194509250565b6001600160a01b03831660009081526004602090815260408083203384529091528120546000198114610fc957610fa483826158ab565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b03851660009081526003602052604081208054859290610ff19084906158ab565b90915550506001600160a01b0380851660008181526003602052604090819020805487019055519091871690600080516020615e638339815191529061103a9087815260200190565b60405180910390a3506001949350505050565b6009546000906001600160a01b0316331461107a576040516282b42960e81b815260040160405180910390fd5b6110c161108a60408401846158be565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506136d992505050565b6111086110d160408401846158be565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061371992505050565b6000611113846137c0565b50905080611134576040516374b3e54160e01b815260040160405180910390fd5b600080808061114b61114588615907565b89610c28565b9350935093509350828760e00135111561117857604051635b688e4760e01b815260040160405180910390fd5b60005b61118860408901896158be565b90508110156112215761120f6111a460408a0160208b016154dc565b306111b260608c018c6158be565b858181106111c2576111c2615853565b905060200201358b80604001906111d991906158be565b868181106111e9576111e9615853565b90506020020160208101906111fe91906154dc565b6001600160a01b031692919061382f565b8061121981615892565b91505061117b565b5061123260e0880160c08901615913565b156112465761124187856138a0565b611250565b6112508784613cb8565b8115611260576112603083613d1c565b61127261126d828a61587f565b613d76565b600254600090611282838b61587f565b61129490670de0b6b3a7640000615930565b61129e919061595d565b90507f27bd68e1c50cdd7ad817c783781d4ff30255bc19b0f9b1eb3477892bc9e38d386112ce60208a018a615971565b6040805163ffffffff90921682526020820184905281018490526060810186905260800160405180910390a150979650505050505050565b6006546001600160a01b03163314611330576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03811661137c576001600160a01b0380831660009081526010602052604090208054918316600160481b02600160481b600160e81b03199092169190911790556115a5565b6000816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e0919061598c565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611422573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611446919061598c565b90506000846001600160a01b0316836001600160a01b03160361146a5750806114a3565b846001600160a01b0316826001600160a01b03160361148a5750816114a3565b60405163d35a91cf60e01b815260040160405180910390fd5b6001600160a01b038581166000908152601060209081526040918290208054600160481b600160e81b031916600160481b8986160217815560010180547fff0000000000000000000000000000000000000000ffffffffffffffffffffff16600160581b948616948502179055815163313ce56760e01b8152915163313ce5679260048082019392918290030181865afa158015611545573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156991906159a9565b6001600160a01b0386166000908152601060205260409020600101805460ff92909216600160501b0260ff60501b199092169190911790555050505b6040516001600160a01b0382811682528316907ff09d9fda2e96eeb85eacfdc7def084e286e39b2c8dab78b35221f9a5e2502cb4906020015b60405180910390a25050565b60007f000000000000000000000000000000000000000000000000000000000000000046146116205761161b613dab565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461168d576040516282b42960e81b815260040160405180910390fd5b6116a16001600160a01b0384168383613e45565b505050565b6006546001600160a01b031633146116d0576040516282b42960e81b815260040160405180910390fd5b600a8161ffff1610806116e857506101f48161ffff16115b1561170657604051636d4d4a6760e11b815260040160405180910390fd5b600b80546affff0000000000000000001916600160481b61ffff8416908102919091179091556040519081527fd08c1bc3993b0af9ff782c23b664467f9c10136abbd2f03262557fc2abde0f5590602001610b22565b6006546001600160a01b03163314611786576040516282b42960e81b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6006546001600160a01b031633146117d2576040516282b42960e81b815260040160405180910390fd5b8281146117f25760405163b1f40f7760e01b815260040160405180910390fd5b60005b838110156118635761185385858381811061181257611812615853565b905060200201602081019061182791906154dc565b84848481811061183957611839615853565b905060200201602081019061184e91906154dc565b613e75565b61185c81615892565b90506117f5565b5050505050565b6006546001600160a01b03163314611894576040516282b42960e81b815260040160405180910390fd5b68056bc75e2d6310000081600f0b13156118c157604051636d4d4a6760e11b815260040160405180910390fd5b600f80546001600160801b03928316600160801b029216919091179055565b600e81815481106118f057600080fd5b6000918252602090912001546001600160a01b0316905081565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611952576040516282b42960e81b815260040160405180910390fd5b6001600160a01b039091166000908152600d6020526040902055565b6007546001600160a01b03163314611998576040516282b42960e81b815260040160405180910390fd5b60068054600780546001600160a01b03198084166001600160a01b038381169182179096559116909155604051929091169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6009546000906001600160a01b03163314611a22576040516282b42960e81b815260040160405180910390fd5b611a3261108a60408401846158be565b611a4261108a60808401846158be565b611a526110d160408401846158be565b611a626110d160808401846158be565b611aa9611a7260408401846158be565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061401c92505050565b611ab9611a7260808401846158be565b6000611ac4846137c0565b50905080611ae5576040516374b3e54160e01b815260040160405180910390fd5b600080611b7f611af860408701876158be565b6000818110611b0957611b09615853565b9050602002016020810190611b1e91906154dc565b611b2b60608801886158be565b6000818110611b3c57611b3c615853565b90506020020135878060800190611b5391906158be565b6000818110611b6457611b64615853565b9050602002016020810190611b7991906154dc565b89613425565b9150915081600003611ba45760405163c573eaa560e01b815260040160405180910390fd5b8460e00135821015611bc957604051635b688e4760e01b815260040160405180910390fd5b81611c00611bda60808801886158be565b6000818110611beb57611beb615853565b90506020020160208101906109a891906154dc565b1015611c1f576040516336eefe3560e01b815260040160405180910390fd5b600080821315611c4d57611c33828861587f565b9050611c4830611c43848a61364c565b613d1c565b611ccb565b6000821215611cc857611c5f826159c6565b611c6990886158ab565b90506000611c7f611c79846159c6565b8961364c565b30600090815260036020526040902054909150811115611cae5730600090815260036020526040902054611cb0565b805b90508015611cc257611cc2308261405c565b50611ccb565b50855b611cd481613d76565b611d34611ce460408801886158be565b6000818110611cf557611cf5615853565b9050602002016020810190611d0a91906154dc565b611d1760608901896158be565b6000818110611d2857611d28615853565b905060200201356140be565b611d70611d4460808801886158be565b6000818110611d5557611d55615853565b9050602002016020810190611d6a91906154dc565b846140ef565b611dca611d8360408801602089016154dc565b30611d9160608a018a6158be565b6000818110611da257611da2615853565b90506020020135898060400190611db991906158be565b60008181106111e9576111e9615853565b611e21611ddd60408801602089016154dc565b84611deb60808a018a6158be565b6000818110611dfc57611dfc615853565b9050602002016020810190611e1191906154dc565b6001600160a01b03169190613e45565b7fc84ce3ed8ab6ac38b6355da334b0da7d1c924c8b5d0e83d53d6883f2be0fcce8611e4f6020880188615971565b611e5c60808901896158be565b6000818110611e6d57611e6d615853565b9050602002016020810190611e8291906154dc565b6040805163ffffffff90931683526001600160a01b039091166020830152810185905260600160405180910390a15095945050505050565b60095460405163b588c10b60e01b81523360048201526001600160a01b039091169063b588c10b90602401602060405180830381865afa158015611f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2691906159e2565b611f42576040516282b42960e81b815260040160405180910390fd5b600f8054600160801b9004900b600882900b1315611f7357604051636d4d4a6760e11b815260040160405180910390fd5b600f54611f8a906001600160801b0316600561587f565b431015611faa576040516311a3df9560e01b815260040160405180910390fd5b600f80546fffffffffffffffffffffffffffffffff1916436001600160801b03161790556001600160a01b038216600081815260106020908152604091829020600101805468ffffffffffffffffff19166001600160481b0386161790559051600884900b81527f05d3a92f1773bfe6b86e42c45a0bfdf57247864d79797482e71c94f22c8dcb2a91016115de565b6009546000906001600160a01b03163314612066576040516282b42960e81b815260040160405180910390fd5b61207661108a60808401846158be565b6120866110d160808401846158be565b6000612091846137c0565b509050806120b2576040516374b3e54160e01b815260040160405180910390fd5b6000806120c560e0860160c08701615913565b6120d8576120d38686614117565b6120e2565b6120e286866142e7565b909250905061216d6120f760808701876158be565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506121369250505060a08801886158be565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506145a092505050565b61217a61126d83886158ab565b600060025460000361218d5760006121b6565b60025461219a84896158ab565b6121ac90670de0b6b3a7640000615930565b6121b6919061595d565b90507f90b5f7dd30f1e6716a37f642aab9e2a5a1216c72e1044251b59c801e40dba82f6121e66020880188615971565b6040805163ffffffff90921682526020820184905281018590526060810184905260800160405180910390a1509095945050505050565b6006546001600160a01b03163314612247576040516282b42960e81b815260040160405180910390fd5b68056bc75e2d63100000816001600160481b0316111561227a57604051636d4d4a6760e11b815260040160405180910390fd5b600b805468ffffffffffffffffff19166001600160481b0383169081179091556040519081527ff036cc909a40e5a5297fc43a607fba898d621fe78a6153d56c6bf249ce92dee490602001610b22565b6001600160a01b038281166000908152601060209081526040808320815160e08101835281546001600160481b0381168252600160481b90819004871694820194909452600190910154600881810b8385015293810460ff9081166060840152600160501b820481166080840152600160581b8204871660a0840152600160f81b90910416151560c0820152915490516378c8814f60e11b8152929391928492919091169063f191029e9061238590889086906004016159ff565b602060405180830381865afa1580156123a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c69190615a88565b90508160600151600a6123d99190615b85565b6123e38286615930565b6123ed919061595d565b95945050505050565b6000806000806000600e80548060200260200160405190810160405280929190818152602001828054801561245457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612436575b505083519394506000925050505b818110156124f25782818151811061247c5761247c615853565b60200260200101519550600c6000876001600160a01b03166001600160a01b0316815260200190815260200160002054600003156124e2576124bd86613141565b9350836000036124d5575050600a5495945050505050565b6124df848661587f565b94505b6124eb81615892565b9050612462565b509295945050505050565b6006546001600160a01b03163314612527576040516282b42960e81b815260040160405180910390fd5b6007546040516001600160a01b03909116907f6ecd4842251bedd053b09547c0fabaab9ec98506ebf24469e8dd5560412ed37f90600090a2600780546001600160a01b0319169055565b60018054610b3a9061581f565b6060600080808061259260808801886158be565b90506001600160401b038111156125ab576125ab6150cc565b6040519080825280602002602001820160405280156125e457816020015b6125d1614fbe565b8152602001906001900390816125c95790505b50945060005b6125f760808901896158be565b905081101561278957600061266061261260808b018b6158be565b8481811061262257612622615853565b905060200201602081019061263791906154dc565b61264460a08c018c6158be565b8581811061265457612654615853565b905060200201356122ca565b9050806000036126835760405163e49d3ed160e01b815260040160405180910390fd5b6040805160e0810190915280601060006126a060808e018e6158be565b878181106126b0576126b0615853565b90506020020160208101906126c591906154dc565b6001600160a01b03168152602080820192909252604001600020546001600160481b03168252016127276126fc60808d018d6158be565b8681811061270c5761270c615853565b905060200201602081019061272191906154dc565b8b613601565b8152602001828152602001600081526020016000815260200160008152602001600081525087838151811061275e5761275e615853565b6020908102919091010152612773818461587f565b925050808061278190615892565b9150506125ea565b5060005b855181101561282d576127cb8682815181106127ab576127ab615853565b6020908102919091010151600b54899085906001600160481b03166145fa565b8682815181106127dd576127dd615853565b602002602001018190525061280f8682815181106127fd576127fd615853565b6020026020010151608001518861364c565b612819908461587f565b92508061282581615892565b91505061278d565b50612838818761364c565b9250612844828461587f565b93509295509295909350565b600b54600090612875906301e187e090600160881b90046001600160481b0316615b94565b600b546001600160481b039190911691506000906128a290600160d01b900465ffffffffffff16426158ab565b9050806000036128b0575050565b6000670de0b6b3a764000060025483856128ca9190615930565b6128d49190615930565b6128de919061595d565b600b80546001600160d01b0316600160d01b4265ffffffffffff160217905590506129093082613d1c565b6040518181527f147fac6415bee3006ba6002a9a6636f492d311690c9e52a2421afc6392e0fb959060200160405180910390a1505050565b6006546001600160a01b0316331461296b576040516282b42960e81b815260040160405180910390fd5b6129748261463d565b61297d81614667565b306000908152600360205260408120805483929061299c9084906158ab565b90915550506001600160a01b038216600090815260036020526040812080548392906129c990849061587f565b90915550506040518181526001600160a01b038316907f9dc46f23cfb5ddcad0ae7ea2be38d47fec07bb9382ec7e564efc69e036dd66ce906020016115de565b33600090815260036020526040812080548391908390612a2a9084906158ab565b90915550506001600160a01b03831660008181526003602052604090819020805485019055513390600080516020615e6383398151915290610c169086815260200190565b6000805b8251811015612b005760106000848381518110612a9257612a92615853565b6020908102919091018101516001600160a01b031682528101919091526040016000206001015460080b68056bc75e2d630fffff1903612aee57828181518110612ade57612ade615853565b6020026020010151915050919050565b80612af881615892565b915050612a73565b50600092915050565b612b4b6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c0810182526001600160a01b0384168082526000818152600c60209081528482205481850152918152600d909152829020549181019190915260608101612b9f84670de0b6b3a76400006122ca565b815260200160008152602001600254600a60000154670de0b6b3a7640000612bc79190615930565b612bd1919061595d565b905292915050565b6006546001600160a01b03163314612c03576040516282b42960e81b815260040160405180910390fd5b600e548114612c255760405163b1f40f7760e01b815260040160405180910390fd5b6000805b82811015612c7657838382818110612c4357612c43615853565b9050602002016020810190612c589190614ffb565b612c629083615bba565b915080612c6e81615892565b915050612c29565b5068056bc75e2fb71be400816001600160481b03161180612ca8575068056bc75e2b0f041c00816001600160481b0316105b15612cc657604051636b522f1160e11b815260040160405180910390fd5b60005b82811015612d6657838382818110612ce357612ce3615853565b9050602002016020810190612cf89190614ffb565b60106000600e8481548110612d0f57612d0f615853565b6000918252602080832091909101546001600160a01b031683528201929092526040019020805468ffffffffffffffffff19166001600160481b039290921691909117905580612d5e81615892565b915050612cc9565b506040517f0f76096615ee194cca6c5e0f25f4a332cbf3aaa195ae55f2cbcb881db1aef18390600090a1505050565b42841015612dea5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b60006001612df66115ea565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015612f02573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590612f385750876001600160a01b0316816001600160a01b0316145b612f755760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401612de1565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6000805b8251811015612b00576010600084838151811061300157613001615853565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600101601f9054906101000a900460ff1661305057828181518110612ade57612ade615853565b8061305a81615892565b915050612fe2565b6001600160a01b0381166000908152600d6020908152604080832054600c909252822054610c2291906158ab565b6009546001600160a01b031633148015906130b657506006546001600160a01b03163314155b156130d3576040516282b42960e81b815260040160405180910390fd5b600b54600160581b900465ffffffffffff164303613104576040516311a3df9560e01b815260040160405180910390fd5b600b805465ffffffffffff60581b1916600160581b4365ffffffffffff16021790556000613131826137c0565b91505061313d81613d76565b5050565b6001600160a01b0381166000908152600c6020526040812054610c229083906122ca565b6006546001600160a01b0316331461318f576040516282b42960e81b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b0383169081179091556040517f90f3093aefb44e115f8088a7f69b5f3adf9d7ec6f153ac758de49cfe3c740cd190600090a250565b6006546001600160a01b03163314613203576040516282b42960e81b815260040160405180910390fd5b6000600e828154811061321857613218615853565b60009182526020808320909101546001600160a01b0316808352600c9091526040909120549091501561325d576040516252b55360e31b815260040160405180910390fd5b6001600160a01b0381166000908152601060205260409020546001600160481b03161561329c576040516252b55360e31b815260040160405180910390fd5b6001600160a01b038116600090815260106020526040812080546001600160e81b0319168155600190810191909155600e805490916132da916158ab565b815481106132ea576132ea615853565b600091825260209091200154600e80546001600160a01b03909216918490811061331657613316615853565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600e80548061335557613355615be1565b600082815260208120820160001990810180546001600160a01b03191690559091019091556040516001600160a01b038316917f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc91a25050565b6006546001600160a01b031633146133d9576040516282b42960e81b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b03831690811790915560405133907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270090600090a350565b600080600061343487876122ca565b6001600160a01b0386166000908152601060205260408120600101549192509061346f90879061069090600160481b900460ff16600a615b85565b905081158061347c575080155b1561348f576000809350935050506135f8565b50506040805160e0810182526001600160a01b038816600090815260106020908152928120546001600160481b031682529181016134cd8987613601565b81526020016134dc89896122ca565b8152600060208083018290526040808401839052606084018390526080909301829052825160e0810184526001600160a01b038a16835260108252928220546001600160481b031683529293509181016135368888613601565b8152600060208083018290526040808401839052606084018390526080840183905260a0909301829052600b546001600160a01b03808e1684526010909252838320600190810154928c1684529383209093015493945090926135b092869286928b926001600160481b031691600890810b91900b614688565b90506135c487670de0b6b3a76400006122ca565b6135d682670de0b6b3a7640000615930565b6135e0919061595d565b8184604001516135f09190615bf7565b945094505050505b94509492505050565b6000811580156136115750600a54155b1561361e57506000610c22565b8161362884613141565b61363b9068056bc75e2d63100000615930565b613645919061595d565b9392505050565b600254600090801561367257826136638286615930565b61366d919061595d565b613674565b835b949350505050565b613684614fbe565b845160000361369e57506040840151608085015283613674565b816000036136ad575083613674565b6136b88585856147e9565b945084606001516000036136cd575083613674565b6123ed858585856148df565b60006136e482612fde565b90506001600160a01b0381161561313d57604051632777a68f60e11b81526001600160a01b0382166004820152602401612de1565b600954604051633e031b6760e21b81526000916001600160a01b03169063f80c6d9c9061374a908590600401615c17565b602060405180830381865afa158015613767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378b919061598c565b90506001600160a01b0381161561313d5760405163fc31f2eb60e01b81526001600160a01b0382166004820152602401612de1565b600b54600a546000918291600160481b90910461ffff1690826137e382846149e9565b905060006137f5838561ffff16614a1a565b90508187101561380d57506000969095509350505050565b8087111561382357600097909650945050505050565b50600196945050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261389a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614a39565b50505050565b60006138af60408401846158be565b90506001600160401b038111156138c8576138c86150cc565b6040519080825280602002602001820160405280156138f1578160200160208202803683370190505b509050600061390360408501856158be565b90506001600160401b0381111561391c5761391c6150cc565b604051908082528060200260200182016040528015613945578160200160208202803683370190505b50905060008060005b61395b60408801886158be565b9050811015613a945785818151811061397657613976615853565b602002602001015160a0015186828151811061399457613994615853565b602002602001015160c00151670de0b6b3a76400006139b39190615930565b6139bd919061595d565b9250670de0b6b3a7640000836139d660608a018a6158be565b848181106139e6576139e6615853565b905060200201356139f79190615930565b613a01919061595d565b848281518110613a1357613a13615853565b602002602001018181525050858181518110613a3157613a31615853565b602002602001015160c00151858281518110613a4f57613a4f615853565b602002602001018181525050848181518110613a6d57613a6d615853565b602002602001015182613a80919061587f565b915080613a8c81615892565b91505061394e565b5060006001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663c92b75c4613ad660408a0160208b016154dc565b613ae360408b018b6158be565b888a886040518763ffffffff1660e01b8152600401613b0796959493929190615c94565b6020604051808303816000875af1158015613b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b4a919061598c565b905060005b613b5c60408901896158be565b9050811015613bb557613ba382868381518110613b7b57613b7b615853565b60200260200101518a8060400190613b9391906158be565b85818110611dfc57611dfc615853565b80613bad81615892565b915050613b4f565b50613c3c613bc660408901896158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613c059250505060608a018a6158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250614b0e92505050565b613c85613c4c60408901896158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250614b68915050565b613caf7f000000000000000000000000000000000000000000000000000000000000000083613d1c565b50505050505050565b613d07613cc860408401846158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613c059250505060608501856158be565b61313d613d1a60408401602085016154dc565b825b8060026000828254613d2e919061587f565b90915550506001600160a01b038216600081815260036020908152604080832080548601905551848152600080516020615e6383398151915291015b60405180910390a35050565b600a8190556040518181527fb4f10f1c952679350ddb7fefb943b40a586171e621e220adfb9ed55f0a643d0f90602001610b22565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051613ddd9190615d21565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6040516001600160a01b0383166024820152604481018290526116a190849063a9059cbb60e01b90606401613863565b6001600160a01b038216600090815260106020526040902060010154600160f81b900460ff1615613ec457604051634f1ac48560e01b81526001600160a01b0383166004820152602401612de1565b6001600160a01b03821660008181526010602090815260409182902060010180546001600160f81b0316600160f81b179055815163313ce56760e01b8152915163313ce5679260048082019392918290030181865afa158015613f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f4f91906159a9565b6001600160a01b0383166000908152601060205260409020600101805460ff92909216600160481b0269ff00000000000000000019909216919091179055613f978282611306565b600e80546001810182556000919091527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd0180546001600160a01b0319166001600160a01b0384169081179091556040519081527f0e3c58ebfb2e7465fbb1c32e6b4f40c3c4f5ca77e8218a386aff8617831260d79060200160405180910390a15050565b600061402782612a6f565b90506001600160a01b0381161561313d576040516303e4acb760e01b81526001600160a01b0382166004820152602401612de1565b6001600160a01b038216600090815260036020526040812080548392906140849084906158ab565b90915550506002805482900390556040518181526000906001600160a01b03841690600080516020615e6383398151915290602001613d6a565b6001600160a01b0382166000908152600c6020526040812080548392906140e690849061587f565b90915550505050565b6001600160a01b0382166000908152600c6020526040812080548392906140e69084906158ab565b60008060005b61412a60808501856158be565b90508110156141ab5761414060a08501856158be565b8281811061415057614150615853565b9050602002013561417a85806080019061416a91906158be565b84818110611beb57611beb615853565b1015614199576040516336eefe3560e01b815260040160405180910390fd5b806141a381615892565b91505061411d565b5060008060006141bb868861257e565b94509450509350508560e001358311156141e857604051635b688e4760e01b815260040160405180910390fd5b82600360006141fd60408a0160208b016154dc565b6001600160a01b03166001600160a01b0316815260200190815260200160002054101561423d57604051637596688560e01b815260040160405180910390fd5b61425661425060408801602089016154dc565b8461405c565b8115614266576142663083613d1c565b60005b61427660808801886158be565b90508110156142d8576142c66142926040890160208a016154dc565b61429f60a08a018a6158be565b848181106142af576142af615853565b90506020020135898060800190613b9391906158be565b806142d081615892565b915050614269565b509350909150505b9250929050565b6000808061433f6142fb60808601866158be565b600081811061430c5761430c615853565b905060200201602081019061432191906154dc565b61432e60a08701876158be565b600081811061265457612654615853565b9050806000036143625760405163e49d3ed160e01b815260040160405180910390fd5b600061436e828761364c565b9050808560e00135101561439557604051635b688e4760e01b815260040160405180910390fd5b6143bf7f00000000000000000000000000000000000000000000000000000000000000008261405c565b6144456143cf60808701876158be565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061440e9250505060a08801886158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250614bf392505050565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016639c787c6761448460408801602089016154dc565b61449160808901896158be565b60008181106144a2576144a2615853565b90506020020160208101906144b791906154dc565b6144c460a08a018a6158be565b60008181106144d5576144d5615853565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501525060209091020135604482015260648101849052608401600060405180830381600087803b15801561453357600080fd5b505af1158015614547573d6000803e3d6000fd5b50614595925061456091505060408701602088016154dc565b61456d60a08801886158be565b600081811061457e5761457e615853565b90506020020135878060800190611deb91906158be565b909590945092505050565b60005b82518110156116a1576145e88382815181106145c1576145c1615853565b60200260200101518383815181106145db576145db615853565b60200260200101516140ef565b806145f281615892565b9150506145a3565b614602614fbe565b81600003614611575083613674565b61461c858585614c7e565b94508460600151600003614631575083613674565b6123ed85858585614d26565b6001600160a01b0381166146645760405163339d6ef160e21b815260040160405180910390fd5b50565b806000036146645760405163339d6ef160e21b815260040160405180910390fd5b6000614697878660008761367c565b9650600068056bc75e2d63100000886060015189604001516146b991906158ab565b6146c39086615dc0565b6146cd9190615df0565b9050600080821215614710576146ed6146e883600019615dc0565b614e15565b89608001518a6040015161470191906158ab565b61470b91906158ab565b614737565b61471982614e15565b89608001518a6040015161472d91906158ab565b614737919061587f565b60408901819052905061474d88886000896145fa565b9750600068056bc75e2d6310000089606001518361476b91906158ab565b6147759087615dc0565b61477f9190615df0565b90506000808212156147b85761479a6146e883600019615dc0565b60808b01516147a990856158ab565b6147b391906158ab565b6147da565b6147c182614e15565b60808b01516147d090856158ab565b6147da919061587f565b9b9a5050505050505050505050565b6147f1614fbe565b600068056bc75e2d6310000061480a8660000151614e3c565b6148178760200151614e3c565b6148219190615bf7565b61482a86614e3c565b6148349190615dc0565b61483e9190615df0565b9050600083600003614851576000614883565b68056bc75e2d6310000061486485614e3c565b875161486f90614e3c565b6148799190615dc0565b6148839190615df0565b9050600081836148968960400151614e3c565b6148a09190615e1e565b6148aa9190615bf7565b90506148cf6146e86148bf8960400151614e3c565b6148ca846000614e66565b614e7d565b6060880152509495945050505050565b6148e7614fbe565b6000856040015168056bc75e2d631000008760200151876149089190615930565b614912919061595d565b61491c919061587f565b865190915060009068056bc75e2d6310000090614939878961587f565b6149439190615930565b61494d919061595d565b90506000670de0b6b3a7640000826149658583615930565b61496f919061595d565b61497991906158ab565b9050600061498f82670de0b6b3a7640000614e8c565b9050600068056bc75e2d631000006149a78389615930565b6149b1919061595d565b9050670de0b6b3a7640000818b606001516149cc9190615930565b6149d6919061595d565b60808b0152509798975050505050505050565b61271081810390821161138819829004841182021715614a0857600080fd5b61271092026113880191909104919050565b61271081016127101982116113881982900484111715614a0857600080fd5b6000614a8e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e9b9092919063ffffffff16565b9050805160001480614aaf575080806020019051810190614aaf91906159e2565b6116a15760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401612de1565b60005b82518110156116a157614b56838281518110614b2f57614b2f615853565b6020026020010151838381518110614b4957614b49615853565b60200260200101516140be565b80614b6081615892565b915050614b11565b60005b82518110156116a157818181518110614b8657614b86615853565b6020026020010151600d6000858481518110614ba457614ba4615853565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254614bdb919061587f565b90915550819050614beb81615892565b915050614b6b565b60005b82518110156116a157818181518110614c1157614c11615853565b6020026020010151600d6000858481518110614c2f57614c2f615853565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254614c6691906158ab565b90915550819050614c7681615892565b915050614bf6565b614c86614fbe565b600068056bc75e2d63100000614c9f8660000151614e3c565b614cac8760200151614e3c565b614cb69190615bf7565b614cbf86614e3c565b614cc99190615dc0565b614cd39190615df0565b9050600068056bc75e2d63100000614cea85614e3c565b8751614cf590614e3c565b614cff9190615dc0565b614d099190615df0565b905060008183614d1c8960400151614e3c565b6148a09190615bf7565b614d2e614fbe565b6000614d3d8660400151614e3c565b68056bc75e2d63100000614d548860200151614e3c565b614d5d88614e3c565b614d679190615dc0565b614d719190615df0565b614d7b9190615bf7565b9050600068056bc75e2d63100000614d9286614e3c565b614d9b88614e3c565b614da59190615bf7565b8851614db090614e3c565b614dba9190615dc0565b614dc49190615df0565b9050600081614ddb84670de0b6b3a7640000615dc0565b614de59190615df0565b614df790670de0b6b3a7640000615bf7565b9050600061498f614e0783614e15565b670de0b6b3a7640000614e8c565b600080821215614e385760405163029f024d60e31b815260040160405180910390fd5b5090565b60006001600160ff1b03821115614e385760405163677c430560e11b815260040160405180910390fd5b600081831215614e765781613645565b5090919050565b6000818312614e765781613645565b6000818310614e765781613645565b6060613674848460008585600080866001600160a01b03168587604051614ec29190615e46565b60006040518083038185875af1925050503d8060008114614eff576040519150601f19603f3d011682016040523d82523d6000602084013e614f04565b606091505b5091509150614f1587838387614f20565b979650505050505050565b60608315614f8f578251600003614f88576001600160a01b0385163b614f885760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401612de1565b5081613674565b6136748383815115614fa45781518083602001fd5b8060405162461bcd60e51b8152600401612de19190615048565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60006020828403121561500d57600080fd5b81356001600160481b038116811461364557600080fd5b60005b8381101561503f578181015183820152602001615027565b50506000910152565b6020815260008251806020840152615067816040850160208701615024565b601f01601f19169190910160400192915050565b6001600160a01b038116811461466457600080fd5b803561509b8161507b565b919050565b600080604083850312156150b357600080fd5b82356150be8161507b565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b0381118282101715615105576151056150cc565b60405290565b604051601f8201601f191681016001600160401b0381118282101715615133576151336150cc565b604052919050565b803563ffffffff8116811461509b57600080fd5b60006001600160401b03821115615168576151686150cc565b5060051b60200190565b600082601f83011261518357600080fd5b813560206151986151938361514f565b61510b565b82815260059290921b840181019181810190868411156151b757600080fd5b8286015b848110156151db5780356151ce8161507b565b83529183019183016151bb565b509695505050505050565b600082601f8301126151f757600080fd5b813560206152076151938361514f565b82815260059290921b8401810191818101908684111561522657600080fd5b8286015b848110156151db578035835291830191830161522a565b801515811461466457600080fd5b803561509b81615241565b6000610100828403121561526d57600080fd5b6152756150e2565b90506152808261513b565b815261528e60208301615090565b602082015260408201356001600160401b03808211156152ad57600080fd5b6152b985838601615172565b604084015260608401359150808211156152d257600080fd5b6152de858386016151e6565b606084015260808401359150808211156152f757600080fd5b61530385838601615172565b608084015260a084013591508082111561531c57600080fd5b50615329848285016151e6565b60a08301525061533b60c0830161524f565b60c082015260e082013560e082015292915050565b6000806040838503121561536357600080fd5b82356001600160401b0381111561537957600080fd5b6153858582860161525a565b95602094909401359450505050565b600081518084526020808501945080840160005b8381101561540257815180518852838101518489015260408082015190890152606080820151908901526080808201519089015260a0808201519089015260c0908101519088015260e090960195908201906001016153a8565b509495945050505050565b6080815260006154206080830187615394565b6020830195909552506040810192909252606090910152919050565b60008060006060848603121561545157600080fd5b833561545c8161507b565b9250602084013561546c8161507b565b929592945050506040919091013590565b6000610100828403121561549057600080fd5b50919050565b600080604083850312156154a957600080fd5b8235915060208301356001600160401b038111156154c657600080fd5b6154d28582860161547d565b9150509250929050565b6000602082840312156154ee57600080fd5b81356136458161507b565b6000806040838503121561550c57600080fd5b82356155178161507b565b915060208301356155278161507b565b809150509250929050565b60006020828403121561554457600080fd5b813561ffff8116811461364557600080fd5b60008083601f84011261556857600080fd5b5081356001600160401b0381111561557f57600080fd5b6020830191508360208260051b85010111156142e057600080fd5b600080600080604085870312156155b057600080fd5b84356001600160401b03808211156155c757600080fd5b6155d388838901615556565b909650945060208701359150808211156155ec57600080fd5b506155f987828801615556565b95989497509550505050565b60006020828403121561561757600080fd5b813580600f0b811461364557600080fd5b60006020828403121561563a57600080fd5b5035919050565b6000806040838503121561565457600080fd5b823561565f8161507b565b91506020830135600881900b811461552757600080fd5b6000806040838503121561568957600080fd5b82356001600160401b0381111561569f57600080fd5b6153858582860161547d565b60a0815260006156be60a0830188615394565b90508560208301528460408301528360608301528260808301529695505050505050565b6000602082840312156156f457600080fd5b81356001600160401b0381111561570a57600080fd5b61367484828501615172565b6000806020838503121561572957600080fd5b82356001600160401b0381111561573f57600080fd5b61574b85828601615556565b90969095509350505050565b60ff8116811461466457600080fd5b600080600080600080600060e0888a03121561578157600080fd5b873561578c8161507b565b9650602088013561579c8161507b565b9550604088013594506060880135935060808801356157ba81615757565b9699959850939692959460a0840135945060c09093013592915050565b600080600080608085870312156157ed57600080fd5b84356157f88161507b565b935060208501359250604085013561580f8161507b565b9396929550929360600135925050565b600181811c9082168061583357607f821691505b60208210810361549057634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610c2257610c22615869565b6000600182016158a4576158a4615869565b5060010190565b81810381811115610c2257610c22615869565b6000808335601e198436030181126158d557600080fd5b8301803591506001600160401b038211156158ef57600080fd5b6020019150600581901b36038213156142e057600080fd5b6000610c22368361525a565b60006020828403121561592557600080fd5b813561364581615241565b8082028115828204841417610c2257610c22615869565b634e487b7160e01b600052601260045260246000fd5b60008261596c5761596c615947565b500490565b60006020828403121561598357600080fd5b6136458261513b565b60006020828403121561599e57600080fd5b81516136458161507b565b6000602082840312156159bb57600080fd5b815161364581615757565b6000600160ff1b82016159db576159db615869565b5060000390565b6000602082840312156159f457600080fd5b815161364581615241565b60006101008201905060018060a01b0380851683526001600160481b03845116602084015280602085015116604084015250604083015160080b606083015260ff606084015116608083015260ff60808401511660a083015260a0830151615a7260c08401826001600160a01b03169052565b5060c083015180151560e0840152509392505050565b600060208284031215615a9a57600080fd5b5051919050565b600181815b80851115615adc578160001904821115615ac257615ac2615869565b80851615615acf57918102915b93841c9390800290615aa6565b509250929050565b600082615af357506001610c22565b81615b0057506000610c22565b8160018114615b165760028114615b2057615b3c565b6001915050610c22565b60ff841115615b3157615b31615869565b50506001821b610c22565b5060208310610133831016604e8410600b8410161715615b5f575081810a610c22565b615b698383615aa1565b8060001904821115615b7d57615b7d615869565b029392505050565b600061364560ff841683615ae4565b60006001600160481b0380841680615bae57615bae615947565b92169190910492915050565b6001600160481b03818116838216019080821115615bda57615bda615869565b5092915050565b634e487b7160e01b600052603160045260246000fd5b8181036000831280158383131683831282161715615bda57615bda615869565b6020808252825182820181905260009190848201906040850190845b81811015615c585783516001600160a01b031683529284019291840191600101615c33565b50909695505050505050565b600081518084526020808501945080840160005b8381101561540257815187529582019590820190600101615c78565b6001600160a01b03878116825260a06020808401829052908301879052600091889160c08501845b8a811015615ce3578435615ccf8161507b565b841682529382019390820190600101615cbc565b508581036040870152615cf6818a615c64565b93505050508281036060840152615d0d8186615c64565b915050826080830152979650505050505050565b600080835481600182811c915080831680615d3d57607f831692505b60208084108203615d5c57634e487b7160e01b86526022600452602486fd5b818015615d705760018114615d8557615db2565b60ff1986168952841515850289019650615db2565b60008a81526020902060005b86811015615daa5781548b820152908501908301615d91565b505084890196505b509498975050505050505050565b80820260008212600160ff1b84141615615ddc57615ddc615869565b8181058314821517610c2257610c22615869565b600082615dff57615dff615947565b600160ff1b821460001984141615615e1957615e19615869565b500590565b8082018281126000831280158216821582161715615e3e57615e3e615869565b505092915050565b60008251615e58818460208701615024565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122068e9ddcfbd3c43085683c87112d80438c0cb8e8db0d4c7ebf93715cd6bbf957f64736f6c6343000813003300000000000000000000000094194de310b99d3c8a5b8c0768cfce7aef81d9be0000000000000000000000009b122361e8708be33b785e44fce4d6ca86ab6c5a000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e100000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc10000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103995760003560e01c806382c0ab21116101e9578063cc88688b1161010f578063e787caa4116100ad578063f2fde38b1161007c578063f2fde38b14610a0c578063f58f951014610a1f578063f6fabac614610a47578063fdc5a0fe14610a6757600080fd5b8063e787caa4146109c0578063eb95c56c146109d3578063ec2a0992146109e6578063f14f58f1146109f957600080fd5b8063db10e60f116100e9578063db10e60f1461095c578063dd62ed3e1461096f578063e02ff0541461099a578063e30c3978146109ad57600080fd5b8063cc88688b146108a2578063d505accf146108b5578063d7691f8f146108c857600080fd5b80639622c75611610187578063a9059cbb11610156578063a9059cbb14610806578063aeabb17f14610819578063b023c8651461082c578063c76ece881461088f57600080fd5b80639622c756146107915780639c016ffd146107b55780639efd6f72146107bd578063a033fcd4146107f357600080fd5b80638be859ec116101c35780638be859ec146107665780638da5cb5b1461076e57806392fede001461078157806395d89b411461078957600080fd5b806382c0ab211461068257806383307f43146106955780638b0dcb4e1461069d57600080fd5b80633745a192116102ce57806371e85c411161026c5780637bcbb1dd1161023b5780637bcbb1dd146106295780637d43447e1461063c5780637ebcf3bf1461064f5780637ecebe001461066257600080fd5b806371e85c41146105e85780637494e604146105fb57806379ba50971461060e5780637acab86e1461061657600080fd5b80636548e9bc116102a85780636548e9bc1461058f578063683ab4a9146105a25780636ede2988146105b557806370a08231146105c857600080fd5b80633745a1921461053e578063439e2e451461056957806352e49dd91461057c57600080fd5b806323b872dd1161033b5780632efda2bc116103155780632efda2bc146104ca578063313ce567146104ea57806335dda72f146105235780633644e5151461053657600080fd5b806323b872dd146104915780632483e715146104a45780632d58fd75146104b757600080fd5b8063095ea7b311610377578063095ea7b3146103f5578063154bb43c1461041857806318160ddd1461043b5780631a366bb71461045257600080fd5b806302e43cbc1461039e5780630505af94146103b357806306fdde03146103e0575b600080fd5b6103b16103ac366004614ffb565b610a6f565b005b600f80546103c891600160801b909104900b81565b604051600f9190910b81526020015b60405180910390f35b6103e8610b2d565b6040516103d79190615048565b6104086104033660046150a0565b610bbb565b60405190151581526020016103d7565b61042b610426366004615350565b610c28565b6040516103d7949392919061540d565b61044460025481565b6040519081526020016103d7565b6104797f000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e181565b6040516001600160a01b0390911681526020016103d7565b61040861049f36600461543c565b610f6d565b600954610479906001600160a01b031681565b6104446104c5366004615496565b61104d565b6104446104d83660046154dc565b600c6020526000908152604090205481565b6105117f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff90911681526020016103d7565b6103b16105313660046154f9565b611306565b6104446115ea565b600f54610551906001600160801b031681565b6040516001600160801b0390911681526020016103d7565b6103b161057736600461543c565b611645565b6103b161058a366004615532565b6116a6565b6103b161059d3660046154dc565b61175c565b6103b16105b036600461559a565b6117a8565b6103b16105c3366004615605565b61186a565b6104446105d63660046154dc565b60036020526000908152604090205481565b6104796105f6366004615628565b6118e0565b6103b16106093660046150a0565b61190a565b6103b161196e565b610444610624366004615496565b6119f5565b6103b1610637366004615641565b611eba565b61044461064a366004615496565b612039565b6103b161065d366004614ffb565b61221d565b6104446106703660046154dc565b60056020526000908152604090205481565b6104446106903660046150a0565b6122ca565b6104446123f6565b61070f6106ab3660046154dc565b601060205260009081526040902080546001909101546001600160481b038216916001600160a01b03600160481b91829004811692600881900b9260ff908204811692600160501b8304821692600160581b810490911691600160f81b9091041687565b604080516001600160481b0390981688526001600160a01b03968716602089015260089590950b9487019490945260ff9283166060870152911660808501529190911660a0830152151560c082015260e0016103d7565b600a54610444565b600654610479906001600160a01b031681565b6103b16124fd565b6103e8612571565b6107a461079f366004615676565b61257e565b6040516103d79594939291906156ab565b6103b1612850565b6105116107cb3660046154dc565b6001600160a01b0316600090815260106020526040902060010154600160481b900460ff1690565b6103b16108013660046150a0565b612941565b6104086108143660046150a0565b612a09565b6104796108273660046156e2565b612a6f565b61083f61083a3660046154dc565b612b09565b6040516103d7919081516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0918201519181019190915260c00190565b6103b161089d366004615716565b612bd9565b600854610479906001600160a01b031681565b6103b16108c3366004615766565b612d95565b600a54600b5461091291906001600160481b038082169161ffff600160481b8204169165ffffffffffff600160581b8304811692600160881b810490921691600160d01b90041686565b604080519687526001600160481b03958616602088015261ffff9094169386019390935265ffffffffffff91821660608601529290921660808401521660a082015260c0016103d7565b61047961096a3660046156e2565b612fde565b61044461097d3660046154f9565b600460209081526000928352604080842090915290825290205481565b6104446109a83660046154dc565b613062565b600754610479906001600160a01b031681565b6103b16109ce366004615628565b613090565b6104446109e13660046154dc565b613141565b6103b16109f43660046154dc565b613165565b6103b1610a07366004615628565b6131d9565b6103b1610a1a3660046154dc565b6133af565b610a32610a2d3660046157d7565b613425565b604080519283526020830191909152016103d7565b610444610a553660046154dc565b600d6020526000908152604090205481565b600e54610444565b6006546001600160a01b03163314610a99576040516282b42960e81b815260040160405180910390fd5b66b1a2bc2ec50000816001600160481b03161115610aca57604051636d4d4a6760e11b815260040160405180910390fd5b600b805468ffffffffffffffffff60881b1916600160881b6001600160481b038416908102919091179091556040519081527f40ecaade69bfd8d44b55fee3f7dc31cdb78157320c6ba966c032db84bd855860906020015b60405180910390a150565b60008054610b3a9061581f565b80601f0160208091040260200160405190810160405280929190818152602001828054610b669061581f565b8015610bb35780601f10610b8857610100808354040283529160200191610bb3565b820191906000526020600020905b815481529060010190602001808311610b9657829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610c169086815260200190565b60405180910390a35060015b92915050565b606060008060008560400151516001600160401b03811115610c4c57610c4c6150cc565b604051908082528060200260200182016040528015610c8557816020015b610c72614fbe565b815260200190600190039081610c6a5790505b50935060005b866040015151811015610e04576000610cde88604001518381518110610cb357610cb3615853565b602002602001015189606001518481518110610cd157610cd1615853565b60200260200101516122ca565b905080600003610d015760405163e49d3ed160e01b815260040160405180910390fd5b6040518060e00160405280601060008b604001518681518110610d2657610d26615853565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060000160009054906101000a90046001600160481b03166001600160481b03168152602001610d9a8a604001518581518110610d8c57610d8c615853565b60200260200101518a613601565b81526020018281526020016000815260200160008152602001610dbd838a61364c565b81526020016000815250868381518110610dd957610dd9615853565b6020908102919091010152610dee818461587f565b9250508080610dfc90615892565b915050610c8b565b5060005b8451811015610f6357610e46858281518110610e2657610e26615853565b6020908102919091010151600b54889085906001600160481b031661367c565b858281518110610e5857610e58615853565b6020026020010181905250610eb2858281518110610e7857610e78615853565b602002602001015160800151868381518110610e9657610e96615853565b602002602001015160400151610eac91906158ab565b8761364c565b858281518110610ec457610ec4615853565b602002602001015160c0018181525050848181518110610ee657610ee6615853565b602002602001015160c0015184610efd919061587f565b9350848181518110610f1157610f11615853565b602002602001015160c00151858281518110610f2f57610f2f615853565b602002602001015160a00151610f4591906158ab565b610f4f908461587f565b925080610f5b81615892565b915050610e08565b5092959194509250565b6001600160a01b03831660009081526004602090815260408083203384529091528120546000198114610fc957610fa483826158ab565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b03851660009081526003602052604081208054859290610ff19084906158ab565b90915550506001600160a01b0380851660008181526003602052604090819020805487019055519091871690600080516020615e638339815191529061103a9087815260200190565b60405180910390a3506001949350505050565b6009546000906001600160a01b0316331461107a576040516282b42960e81b815260040160405180910390fd5b6110c161108a60408401846158be565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506136d992505050565b6111086110d160408401846158be565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061371992505050565b6000611113846137c0565b50905080611134576040516374b3e54160e01b815260040160405180910390fd5b600080808061114b61114588615907565b89610c28565b9350935093509350828760e00135111561117857604051635b688e4760e01b815260040160405180910390fd5b60005b61118860408901896158be565b90508110156112215761120f6111a460408a0160208b016154dc565b306111b260608c018c6158be565b858181106111c2576111c2615853565b905060200201358b80604001906111d991906158be565b868181106111e9576111e9615853565b90506020020160208101906111fe91906154dc565b6001600160a01b031692919061382f565b8061121981615892565b91505061117b565b5061123260e0880160c08901615913565b156112465761124187856138a0565b611250565b6112508784613cb8565b8115611260576112603083613d1c565b61127261126d828a61587f565b613d76565b600254600090611282838b61587f565b61129490670de0b6b3a7640000615930565b61129e919061595d565b90507f27bd68e1c50cdd7ad817c783781d4ff30255bc19b0f9b1eb3477892bc9e38d386112ce60208a018a615971565b6040805163ffffffff90921682526020820184905281018490526060810186905260800160405180910390a150979650505050505050565b6006546001600160a01b03163314611330576040516282b42960e81b815260040160405180910390fd5b6001600160a01b03811661137c576001600160a01b0380831660009081526010602052604090208054918316600160481b02600160481b600160e81b03199092169190911790556115a5565b6000816001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e0919061598c565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611422573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611446919061598c565b90506000846001600160a01b0316836001600160a01b03160361146a5750806114a3565b846001600160a01b0316826001600160a01b03160361148a5750816114a3565b60405163d35a91cf60e01b815260040160405180910390fd5b6001600160a01b038581166000908152601060209081526040918290208054600160481b600160e81b031916600160481b8986160217815560010180547fff0000000000000000000000000000000000000000ffffffffffffffffffffff16600160581b948616948502179055815163313ce56760e01b8152915163313ce5679260048082019392918290030181865afa158015611545573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156991906159a9565b6001600160a01b0386166000908152601060205260409020600101805460ff92909216600160501b0260ff60501b199092169190911790555050505b6040516001600160a01b0382811682528316907ff09d9fda2e96eeb85eacfdc7def084e286e39b2c8dab78b35221f9a5e2502cb4906020015b60405180910390a25050565b60007f000000000000000000000000000000000000000000000000000000000000000146146116205761161b613dab565b905090565b507f654f2e151e312aaa03257bfcb0557766569b89904f51ac099a50f8b945511b2b90565b336001600160a01b037f000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e1161461168d576040516282b42960e81b815260040160405180910390fd5b6116a16001600160a01b0384168383613e45565b505050565b6006546001600160a01b031633146116d0576040516282b42960e81b815260040160405180910390fd5b600a8161ffff1610806116e857506101f48161ffff16115b1561170657604051636d4d4a6760e11b815260040160405180910390fd5b600b80546affff0000000000000000001916600160481b61ffff8416908102919091179091556040519081527fd08c1bc3993b0af9ff782c23b664467f9c10136abbd2f03262557fc2abde0f5590602001610b22565b6006546001600160a01b03163314611786576040516282b42960e81b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6006546001600160a01b031633146117d2576040516282b42960e81b815260040160405180910390fd5b8281146117f25760405163b1f40f7760e01b815260040160405180910390fd5b60005b838110156118635761185385858381811061181257611812615853565b905060200201602081019061182791906154dc565b84848481811061183957611839615853565b905060200201602081019061184e91906154dc565b613e75565b61185c81615892565b90506117f5565b5050505050565b6006546001600160a01b03163314611894576040516282b42960e81b815260040160405180910390fd5b68056bc75e2d6310000081600f0b13156118c157604051636d4d4a6760e11b815260040160405180910390fd5b600f80546001600160801b03928316600160801b029216919091179055565b600e81815481106118f057600080fd5b6000918252602090912001546001600160a01b0316905081565b336001600160a01b037f000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e11614611952576040516282b42960e81b815260040160405180910390fd5b6001600160a01b039091166000908152600d6020526040902055565b6007546001600160a01b03163314611998576040516282b42960e81b815260040160405180910390fd5b60068054600780546001600160a01b03198084166001600160a01b038381169182179096559116909155604051929091169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6009546000906001600160a01b03163314611a22576040516282b42960e81b815260040160405180910390fd5b611a3261108a60408401846158be565b611a4261108a60808401846158be565b611a526110d160408401846158be565b611a626110d160808401846158be565b611aa9611a7260408401846158be565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061401c92505050565b611ab9611a7260808401846158be565b6000611ac4846137c0565b50905080611ae5576040516374b3e54160e01b815260040160405180910390fd5b600080611b7f611af860408701876158be565b6000818110611b0957611b09615853565b9050602002016020810190611b1e91906154dc565b611b2b60608801886158be565b6000818110611b3c57611b3c615853565b90506020020135878060800190611b5391906158be565b6000818110611b6457611b64615853565b9050602002016020810190611b7991906154dc565b89613425565b9150915081600003611ba45760405163c573eaa560e01b815260040160405180910390fd5b8460e00135821015611bc957604051635b688e4760e01b815260040160405180910390fd5b81611c00611bda60808801886158be565b6000818110611beb57611beb615853565b90506020020160208101906109a891906154dc565b1015611c1f576040516336eefe3560e01b815260040160405180910390fd5b600080821315611c4d57611c33828861587f565b9050611c4830611c43848a61364c565b613d1c565b611ccb565b6000821215611cc857611c5f826159c6565b611c6990886158ab565b90506000611c7f611c79846159c6565b8961364c565b30600090815260036020526040902054909150811115611cae5730600090815260036020526040902054611cb0565b805b90508015611cc257611cc2308261405c565b50611ccb565b50855b611cd481613d76565b611d34611ce460408801886158be565b6000818110611cf557611cf5615853565b9050602002016020810190611d0a91906154dc565b611d1760608901896158be565b6000818110611d2857611d28615853565b905060200201356140be565b611d70611d4460808801886158be565b6000818110611d5557611d55615853565b9050602002016020810190611d6a91906154dc565b846140ef565b611dca611d8360408801602089016154dc565b30611d9160608a018a6158be565b6000818110611da257611da2615853565b90506020020135898060400190611db991906158be565b60008181106111e9576111e9615853565b611e21611ddd60408801602089016154dc565b84611deb60808a018a6158be565b6000818110611dfc57611dfc615853565b9050602002016020810190611e1191906154dc565b6001600160a01b03169190613e45565b7fc84ce3ed8ab6ac38b6355da334b0da7d1c924c8b5d0e83d53d6883f2be0fcce8611e4f6020880188615971565b611e5c60808901896158be565b6000818110611e6d57611e6d615853565b9050602002016020810190611e8291906154dc565b6040805163ffffffff90931683526001600160a01b039091166020830152810185905260600160405180910390a15095945050505050565b60095460405163b588c10b60e01b81523360048201526001600160a01b039091169063b588c10b90602401602060405180830381865afa158015611f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2691906159e2565b611f42576040516282b42960e81b815260040160405180910390fd5b600f8054600160801b9004900b600882900b1315611f7357604051636d4d4a6760e11b815260040160405180910390fd5b600f54611f8a906001600160801b0316600561587f565b431015611faa576040516311a3df9560e01b815260040160405180910390fd5b600f80546fffffffffffffffffffffffffffffffff1916436001600160801b03161790556001600160a01b038216600081815260106020908152604091829020600101805468ffffffffffffffffff19166001600160481b0386161790559051600884900b81527f05d3a92f1773bfe6b86e42c45a0bfdf57247864d79797482e71c94f22c8dcb2a91016115de565b6009546000906001600160a01b03163314612066576040516282b42960e81b815260040160405180910390fd5b61207661108a60808401846158be565b6120866110d160808401846158be565b6000612091846137c0565b509050806120b2576040516374b3e54160e01b815260040160405180910390fd5b6000806120c560e0860160c08701615913565b6120d8576120d38686614117565b6120e2565b6120e286866142e7565b909250905061216d6120f760808701876158be565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506121369250505060a08801886158be565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506145a092505050565b61217a61126d83886158ab565b600060025460000361218d5760006121b6565b60025461219a84896158ab565b6121ac90670de0b6b3a7640000615930565b6121b6919061595d565b90507f90b5f7dd30f1e6716a37f642aab9e2a5a1216c72e1044251b59c801e40dba82f6121e66020880188615971565b6040805163ffffffff90921682526020820184905281018590526060810184905260800160405180910390a1509095945050505050565b6006546001600160a01b03163314612247576040516282b42960e81b815260040160405180910390fd5b68056bc75e2d63100000816001600160481b0316111561227a57604051636d4d4a6760e11b815260040160405180910390fd5b600b805468ffffffffffffffffff19166001600160481b0383169081179091556040519081527ff036cc909a40e5a5297fc43a607fba898d621fe78a6153d56c6bf249ce92dee490602001610b22565b6001600160a01b038281166000908152601060209081526040808320815160e08101835281546001600160481b0381168252600160481b90819004871694820194909452600190910154600881810b8385015293810460ff9081166060840152600160501b820481166080840152600160581b8204871660a0840152600160f81b90910416151560c0820152915490516378c8814f60e11b8152929391928492919091169063f191029e9061238590889086906004016159ff565b602060405180830381865afa1580156123a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c69190615a88565b90508160600151600a6123d99190615b85565b6123e38286615930565b6123ed919061595d565b95945050505050565b6000806000806000600e80548060200260200160405190810160405280929190818152602001828054801561245457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612436575b505083519394506000925050505b818110156124f25782818151811061247c5761247c615853565b60200260200101519550600c6000876001600160a01b03166001600160a01b0316815260200190815260200160002054600003156124e2576124bd86613141565b9350836000036124d5575050600a5495945050505050565b6124df848661587f565b94505b6124eb81615892565b9050612462565b509295945050505050565b6006546001600160a01b03163314612527576040516282b42960e81b815260040160405180910390fd5b6007546040516001600160a01b03909116907f6ecd4842251bedd053b09547c0fabaab9ec98506ebf24469e8dd5560412ed37f90600090a2600780546001600160a01b0319169055565b60018054610b3a9061581f565b6060600080808061259260808801886158be565b90506001600160401b038111156125ab576125ab6150cc565b6040519080825280602002602001820160405280156125e457816020015b6125d1614fbe565b8152602001906001900390816125c95790505b50945060005b6125f760808901896158be565b905081101561278957600061266061261260808b018b6158be565b8481811061262257612622615853565b905060200201602081019061263791906154dc565b61264460a08c018c6158be565b8581811061265457612654615853565b905060200201356122ca565b9050806000036126835760405163e49d3ed160e01b815260040160405180910390fd5b6040805160e0810190915280601060006126a060808e018e6158be565b878181106126b0576126b0615853565b90506020020160208101906126c591906154dc565b6001600160a01b03168152602080820192909252604001600020546001600160481b03168252016127276126fc60808d018d6158be565b8681811061270c5761270c615853565b905060200201602081019061272191906154dc565b8b613601565b8152602001828152602001600081526020016000815260200160008152602001600081525087838151811061275e5761275e615853565b6020908102919091010152612773818461587f565b925050808061278190615892565b9150506125ea565b5060005b855181101561282d576127cb8682815181106127ab576127ab615853565b6020908102919091010151600b54899085906001600160481b03166145fa565b8682815181106127dd576127dd615853565b602002602001018190525061280f8682815181106127fd576127fd615853565b6020026020010151608001518861364c565b612819908461587f565b92508061282581615892565b91505061278d565b50612838818761364c565b9250612844828461587f565b93509295509295909350565b600b54600090612875906301e187e090600160881b90046001600160481b0316615b94565b600b546001600160481b039190911691506000906128a290600160d01b900465ffffffffffff16426158ab565b9050806000036128b0575050565b6000670de0b6b3a764000060025483856128ca9190615930565b6128d49190615930565b6128de919061595d565b600b80546001600160d01b0316600160d01b4265ffffffffffff160217905590506129093082613d1c565b6040518181527f147fac6415bee3006ba6002a9a6636f492d311690c9e52a2421afc6392e0fb959060200160405180910390a1505050565b6006546001600160a01b0316331461296b576040516282b42960e81b815260040160405180910390fd5b6129748261463d565b61297d81614667565b306000908152600360205260408120805483929061299c9084906158ab565b90915550506001600160a01b038216600090815260036020526040812080548392906129c990849061587f565b90915550506040518181526001600160a01b038316907f9dc46f23cfb5ddcad0ae7ea2be38d47fec07bb9382ec7e564efc69e036dd66ce906020016115de565b33600090815260036020526040812080548391908390612a2a9084906158ab565b90915550506001600160a01b03831660008181526003602052604090819020805485019055513390600080516020615e6383398151915290610c169086815260200190565b6000805b8251811015612b005760106000848381518110612a9257612a92615853565b6020908102919091018101516001600160a01b031682528101919091526040016000206001015460080b68056bc75e2d630fffff1903612aee57828181518110612ade57612ade615853565b6020026020010151915050919050565b80612af881615892565b915050612a73565b50600092915050565b612b4b6040518060c0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160c0810182526001600160a01b0384168082526000818152600c60209081528482205481850152918152600d909152829020549181019190915260608101612b9f84670de0b6b3a76400006122ca565b815260200160008152602001600254600a60000154670de0b6b3a7640000612bc79190615930565b612bd1919061595d565b905292915050565b6006546001600160a01b03163314612c03576040516282b42960e81b815260040160405180910390fd5b600e548114612c255760405163b1f40f7760e01b815260040160405180910390fd5b6000805b82811015612c7657838382818110612c4357612c43615853565b9050602002016020810190612c589190614ffb565b612c629083615bba565b915080612c6e81615892565b915050612c29565b5068056bc75e2fb71be400816001600160481b03161180612ca8575068056bc75e2b0f041c00816001600160481b0316105b15612cc657604051636b522f1160e11b815260040160405180910390fd5b60005b82811015612d6657838382818110612ce357612ce3615853565b9050602002016020810190612cf89190614ffb565b60106000600e8481548110612d0f57612d0f615853565b6000918252602080832091909101546001600160a01b031683528201929092526040019020805468ffffffffffffffffff19166001600160481b039290921691909117905580612d5e81615892565b915050612cc9565b506040517f0f76096615ee194cca6c5e0f25f4a332cbf3aaa195ae55f2cbcb881db1aef18390600090a1505050565b42841015612dea5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b60006001612df66115ea565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015612f02573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590612f385750876001600160a01b0316816001600160a01b0316145b612f755760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401612de1565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6000805b8251811015612b00576010600084838151811061300157613001615853565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600101601f9054906101000a900460ff1661305057828181518110612ade57612ade615853565b8061305a81615892565b915050612fe2565b6001600160a01b0381166000908152600d6020908152604080832054600c909252822054610c2291906158ab565b6009546001600160a01b031633148015906130b657506006546001600160a01b03163314155b156130d3576040516282b42960e81b815260040160405180910390fd5b600b54600160581b900465ffffffffffff164303613104576040516311a3df9560e01b815260040160405180910390fd5b600b805465ffffffffffff60581b1916600160581b4365ffffffffffff16021790556000613131826137c0565b91505061313d81613d76565b5050565b6001600160a01b0381166000908152600c6020526040812054610c229083906122ca565b6006546001600160a01b0316331461318f576040516282b42960e81b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b0383169081179091556040517f90f3093aefb44e115f8088a7f69b5f3adf9d7ec6f153ac758de49cfe3c740cd190600090a250565b6006546001600160a01b03163314613203576040516282b42960e81b815260040160405180910390fd5b6000600e828154811061321857613218615853565b60009182526020808320909101546001600160a01b0316808352600c9091526040909120549091501561325d576040516252b55360e31b815260040160405180910390fd5b6001600160a01b0381166000908152601060205260409020546001600160481b03161561329c576040516252b55360e31b815260040160405180910390fd5b6001600160a01b038116600090815260106020526040812080546001600160e81b0319168155600190810191909155600e805490916132da916158ab565b815481106132ea576132ea615853565b600091825260209091200154600e80546001600160a01b03909216918490811061331657613316615853565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600e80548061335557613355615be1565b600082815260208120820160001990810180546001600160a01b03191690559091019091556040516001600160a01b038316917f37803e2125c48ee96c38ddf04e826daf335b0e1603579040fd275aba6d06b6fc91a25050565b6006546001600160a01b031633146133d9576040516282b42960e81b815260040160405180910390fd5b600780546001600160a01b0319166001600160a01b03831690811790915560405133907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270090600090a350565b600080600061343487876122ca565b6001600160a01b0386166000908152601060205260408120600101549192509061346f90879061069090600160481b900460ff16600a615b85565b905081158061347c575080155b1561348f576000809350935050506135f8565b50506040805160e0810182526001600160a01b038816600090815260106020908152928120546001600160481b031682529181016134cd8987613601565b81526020016134dc89896122ca565b8152600060208083018290526040808401839052606084018390526080909301829052825160e0810184526001600160a01b038a16835260108252928220546001600160481b031683529293509181016135368888613601565b8152600060208083018290526040808401839052606084018390526080840183905260a0909301829052600b546001600160a01b03808e1684526010909252838320600190810154928c1684529383209093015493945090926135b092869286928b926001600160481b031691600890810b91900b614688565b90506135c487670de0b6b3a76400006122ca565b6135d682670de0b6b3a7640000615930565b6135e0919061595d565b8184604001516135f09190615bf7565b945094505050505b94509492505050565b6000811580156136115750600a54155b1561361e57506000610c22565b8161362884613141565b61363b9068056bc75e2d63100000615930565b613645919061595d565b9392505050565b600254600090801561367257826136638286615930565b61366d919061595d565b613674565b835b949350505050565b613684614fbe565b845160000361369e57506040840151608085015283613674565b816000036136ad575083613674565b6136b88585856147e9565b945084606001516000036136cd575083613674565b6123ed858585856148df565b60006136e482612fde565b90506001600160a01b0381161561313d57604051632777a68f60e11b81526001600160a01b0382166004820152602401612de1565b600954604051633e031b6760e21b81526000916001600160a01b03169063f80c6d9c9061374a908590600401615c17565b602060405180830381865afa158015613767573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061378b919061598c565b90506001600160a01b0381161561313d5760405163fc31f2eb60e01b81526001600160a01b0382166004820152602401612de1565b600b54600a546000918291600160481b90910461ffff1690826137e382846149e9565b905060006137f5838561ffff16614a1a565b90508187101561380d57506000969095509350505050565b8087111561382357600097909650945050505050565b50600196945050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261389a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614a39565b50505050565b60006138af60408401846158be565b90506001600160401b038111156138c8576138c86150cc565b6040519080825280602002602001820160405280156138f1578160200160208202803683370190505b509050600061390360408501856158be565b90506001600160401b0381111561391c5761391c6150cc565b604051908082528060200260200182016040528015613945578160200160208202803683370190505b50905060008060005b61395b60408801886158be565b9050811015613a945785818151811061397657613976615853565b602002602001015160a0015186828151811061399457613994615853565b602002602001015160c00151670de0b6b3a76400006139b39190615930565b6139bd919061595d565b9250670de0b6b3a7640000836139d660608a018a6158be565b848181106139e6576139e6615853565b905060200201356139f79190615930565b613a01919061595d565b848281518110613a1357613a13615853565b602002602001018181525050858181518110613a3157613a31615853565b602002602001015160c00151858281518110613a4f57613a4f615853565b602002602001018181525050848181518110613a6d57613a6d615853565b602002602001015182613a80919061587f565b915080613a8c81615892565b91505061394e565b5060006001600160a01b037f000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e11663c92b75c4613ad660408a0160208b016154dc565b613ae360408b018b6158be565b888a886040518763ffffffff1660e01b8152600401613b0796959493929190615c94565b6020604051808303816000875af1158015613b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b4a919061598c565b905060005b613b5c60408901896158be565b9050811015613bb557613ba382868381518110613b7b57613b7b615853565b60200260200101518a8060400190613b9391906158be565b85818110611dfc57611dfc615853565b80613bad81615892565b915050613b4f565b50613c3c613bc660408901896158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613c059250505060608a018a6158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250614b0e92505050565b613c85613c4c60408901896158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250889250614b68915050565b613caf7f000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e183613d1c565b50505050505050565b613d07613cc860408401846158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613c059250505060608501856158be565b61313d613d1a60408401602085016154dc565b825b8060026000828254613d2e919061587f565b90915550506001600160a01b038216600081815260036020908152604080832080548601905551848152600080516020615e6383398151915291015b60405180910390a35050565b600a8190556040518181527fb4f10f1c952679350ddb7fefb943b40a586171e621e220adfb9ed55f0a643d0f90602001610b22565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051613ddd9190615d21565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6040516001600160a01b0383166024820152604481018290526116a190849063a9059cbb60e01b90606401613863565b6001600160a01b038216600090815260106020526040902060010154600160f81b900460ff1615613ec457604051634f1ac48560e01b81526001600160a01b0383166004820152602401612de1565b6001600160a01b03821660008181526010602090815260409182902060010180546001600160f81b0316600160f81b179055815163313ce56760e01b8152915163313ce5679260048082019392918290030181865afa158015613f2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f4f91906159a9565b6001600160a01b0383166000908152601060205260409020600101805460ff92909216600160481b0269ff00000000000000000019909216919091179055613f978282611306565b600e80546001810182556000919091527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd0180546001600160a01b0319166001600160a01b0384169081179091556040519081527f0e3c58ebfb2e7465fbb1c32e6b4f40c3c4f5ca77e8218a386aff8617831260d79060200160405180910390a15050565b600061402782612a6f565b90506001600160a01b0381161561313d576040516303e4acb760e01b81526001600160a01b0382166004820152602401612de1565b6001600160a01b038216600090815260036020526040812080548392906140849084906158ab565b90915550506002805482900390556040518181526000906001600160a01b03841690600080516020615e6383398151915290602001613d6a565b6001600160a01b0382166000908152600c6020526040812080548392906140e690849061587f565b90915550505050565b6001600160a01b0382166000908152600c6020526040812080548392906140e69084906158ab565b60008060005b61412a60808501856158be565b90508110156141ab5761414060a08501856158be565b8281811061415057614150615853565b9050602002013561417a85806080019061416a91906158be565b84818110611beb57611beb615853565b1015614199576040516336eefe3560e01b815260040160405180910390fd5b806141a381615892565b91505061411d565b5060008060006141bb868861257e565b94509450509350508560e001358311156141e857604051635b688e4760e01b815260040160405180910390fd5b82600360006141fd60408a0160208b016154dc565b6001600160a01b03166001600160a01b0316815260200190815260200160002054101561423d57604051637596688560e01b815260040160405180910390fd5b61425661425060408801602089016154dc565b8461405c565b8115614266576142663083613d1c565b60005b61427660808801886158be565b90508110156142d8576142c66142926040890160208a016154dc565b61429f60a08a018a6158be565b848181106142af576142af615853565b90506020020135898060800190613b9391906158be565b806142d081615892565b915050614269565b509350909150505b9250929050565b6000808061433f6142fb60808601866158be565b600081811061430c5761430c615853565b905060200201602081019061432191906154dc565b61432e60a08701876158be565b600081811061265457612654615853565b9050806000036143625760405163e49d3ed160e01b815260040160405180910390fd5b600061436e828761364c565b9050808560e00135101561439557604051635b688e4760e01b815260040160405180910390fd5b6143bf7f000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e18261405c565b6144456143cf60808701876158be565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061440e9250505060a08801886158be565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250614bf392505050565b6001600160a01b037f000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e116639c787c6761448460408801602089016154dc565b61449160808901896158be565b60008181106144a2576144a2615853565b90506020020160208101906144b791906154dc565b6144c460a08a018a6158be565b60008181106144d5576144d5615853565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501525060209091020135604482015260648101849052608401600060405180830381600087803b15801561453357600080fd5b505af1158015614547573d6000803e3d6000fd5b50614595925061456091505060408701602088016154dc565b61456d60a08801886158be565b600081811061457e5761457e615853565b90506020020135878060800190611deb91906158be565b909590945092505050565b60005b82518110156116a1576145e88382815181106145c1576145c1615853565b60200260200101518383815181106145db576145db615853565b60200260200101516140ef565b806145f281615892565b9150506145a3565b614602614fbe565b81600003614611575083613674565b61461c858585614c7e565b94508460600151600003614631575083613674565b6123ed85858585614d26565b6001600160a01b0381166146645760405163339d6ef160e21b815260040160405180910390fd5b50565b806000036146645760405163339d6ef160e21b815260040160405180910390fd5b6000614697878660008761367c565b9650600068056bc75e2d63100000886060015189604001516146b991906158ab565b6146c39086615dc0565b6146cd9190615df0565b9050600080821215614710576146ed6146e883600019615dc0565b614e15565b89608001518a6040015161470191906158ab565b61470b91906158ab565b614737565b61471982614e15565b89608001518a6040015161472d91906158ab565b614737919061587f565b60408901819052905061474d88886000896145fa565b9750600068056bc75e2d6310000089606001518361476b91906158ab565b6147759087615dc0565b61477f9190615df0565b90506000808212156147b85761479a6146e883600019615dc0565b60808b01516147a990856158ab565b6147b391906158ab565b6147da565b6147c182614e15565b60808b01516147d090856158ab565b6147da919061587f565b9b9a5050505050505050505050565b6147f1614fbe565b600068056bc75e2d6310000061480a8660000151614e3c565b6148178760200151614e3c565b6148219190615bf7565b61482a86614e3c565b6148349190615dc0565b61483e9190615df0565b9050600083600003614851576000614883565b68056bc75e2d6310000061486485614e3c565b875161486f90614e3c565b6148799190615dc0565b6148839190615df0565b9050600081836148968960400151614e3c565b6148a09190615e1e565b6148aa9190615bf7565b90506148cf6146e86148bf8960400151614e3c565b6148ca846000614e66565b614e7d565b6060880152509495945050505050565b6148e7614fbe565b6000856040015168056bc75e2d631000008760200151876149089190615930565b614912919061595d565b61491c919061587f565b865190915060009068056bc75e2d6310000090614939878961587f565b6149439190615930565b61494d919061595d565b90506000670de0b6b3a7640000826149658583615930565b61496f919061595d565b61497991906158ab565b9050600061498f82670de0b6b3a7640000614e8c565b9050600068056bc75e2d631000006149a78389615930565b6149b1919061595d565b9050670de0b6b3a7640000818b606001516149cc9190615930565b6149d6919061595d565b60808b0152509798975050505050505050565b61271081810390821161138819829004841182021715614a0857600080fd5b61271092026113880191909104919050565b61271081016127101982116113881982900484111715614a0857600080fd5b6000614a8e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e9b9092919063ffffffff16565b9050805160001480614aaf575080806020019051810190614aaf91906159e2565b6116a15760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401612de1565b60005b82518110156116a157614b56838281518110614b2f57614b2f615853565b6020026020010151838381518110614b4957614b49615853565b60200260200101516140be565b80614b6081615892565b915050614b11565b60005b82518110156116a157818181518110614b8657614b86615853565b6020026020010151600d6000858481518110614ba457614ba4615853565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254614bdb919061587f565b90915550819050614beb81615892565b915050614b6b565b60005b82518110156116a157818181518110614c1157614c11615853565b6020026020010151600d6000858481518110614c2f57614c2f615853565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254614c6691906158ab565b90915550819050614c7681615892565b915050614bf6565b614c86614fbe565b600068056bc75e2d63100000614c9f8660000151614e3c565b614cac8760200151614e3c565b614cb69190615bf7565b614cbf86614e3c565b614cc99190615dc0565b614cd39190615df0565b9050600068056bc75e2d63100000614cea85614e3c565b8751614cf590614e3c565b614cff9190615dc0565b614d099190615df0565b905060008183614d1c8960400151614e3c565b6148a09190615bf7565b614d2e614fbe565b6000614d3d8660400151614e3c565b68056bc75e2d63100000614d548860200151614e3c565b614d5d88614e3c565b614d679190615dc0565b614d719190615df0565b614d7b9190615bf7565b9050600068056bc75e2d63100000614d9286614e3c565b614d9b88614e3c565b614da59190615bf7565b8851614db090614e3c565b614dba9190615dc0565b614dc49190615df0565b9050600081614ddb84670de0b6b3a7640000615dc0565b614de59190615df0565b614df790670de0b6b3a7640000615bf7565b9050600061498f614e0783614e15565b670de0b6b3a7640000614e8c565b600080821215614e385760405163029f024d60e31b815260040160405180910390fd5b5090565b60006001600160ff1b03821115614e385760405163677c430560e11b815260040160405180910390fd5b600081831215614e765781613645565b5090919050565b6000818312614e765781613645565b6000818310614e765781613645565b6060613674848460008585600080866001600160a01b03168587604051614ec29190615e46565b60006040518083038185875af1925050503d8060008114614eff576040519150601f19603f3d011682016040523d82523d6000602084013e614f04565b606091505b5091509150614f1587838387614f20565b979650505050505050565b60608315614f8f578251600003614f88576001600160a01b0385163b614f885760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401612de1565b5081613674565b6136748383815115614fa45781518083602001fd5b8060405162461bcd60e51b8152600401612de19190615048565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60006020828403121561500d57600080fd5b81356001600160481b038116811461364557600080fd5b60005b8381101561503f578181015183820152602001615027565b50506000910152565b6020815260008251806020840152615067816040850160208701615024565b601f01601f19169190910160400192915050565b6001600160a01b038116811461466457600080fd5b803561509b8161507b565b919050565b600080604083850312156150b357600080fd5b82356150be8161507b565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b0381118282101715615105576151056150cc565b60405290565b604051601f8201601f191681016001600160401b0381118282101715615133576151336150cc565b604052919050565b803563ffffffff8116811461509b57600080fd5b60006001600160401b03821115615168576151686150cc565b5060051b60200190565b600082601f83011261518357600080fd5b813560206151986151938361514f565b61510b565b82815260059290921b840181019181810190868411156151b757600080fd5b8286015b848110156151db5780356151ce8161507b565b83529183019183016151bb565b509695505050505050565b600082601f8301126151f757600080fd5b813560206152076151938361514f565b82815260059290921b8401810191818101908684111561522657600080fd5b8286015b848110156151db578035835291830191830161522a565b801515811461466457600080fd5b803561509b81615241565b6000610100828403121561526d57600080fd5b6152756150e2565b90506152808261513b565b815261528e60208301615090565b602082015260408201356001600160401b03808211156152ad57600080fd5b6152b985838601615172565b604084015260608401359150808211156152d257600080fd5b6152de858386016151e6565b606084015260808401359150808211156152f757600080fd5b61530385838601615172565b608084015260a084013591508082111561531c57600080fd5b50615329848285016151e6565b60a08301525061533b60c0830161524f565b60c082015260e082013560e082015292915050565b6000806040838503121561536357600080fd5b82356001600160401b0381111561537957600080fd5b6153858582860161525a565b95602094909401359450505050565b600081518084526020808501945080840160005b8381101561540257815180518852838101518489015260408082015190890152606080820151908901526080808201519089015260a0808201519089015260c0908101519088015260e090960195908201906001016153a8565b509495945050505050565b6080815260006154206080830187615394565b6020830195909552506040810192909252606090910152919050565b60008060006060848603121561545157600080fd5b833561545c8161507b565b9250602084013561546c8161507b565b929592945050506040919091013590565b6000610100828403121561549057600080fd5b50919050565b600080604083850312156154a957600080fd5b8235915060208301356001600160401b038111156154c657600080fd5b6154d28582860161547d565b9150509250929050565b6000602082840312156154ee57600080fd5b81356136458161507b565b6000806040838503121561550c57600080fd5b82356155178161507b565b915060208301356155278161507b565b809150509250929050565b60006020828403121561554457600080fd5b813561ffff8116811461364557600080fd5b60008083601f84011261556857600080fd5b5081356001600160401b0381111561557f57600080fd5b6020830191508360208260051b85010111156142e057600080fd5b600080600080604085870312156155b057600080fd5b84356001600160401b03808211156155c757600080fd5b6155d388838901615556565b909650945060208701359150808211156155ec57600080fd5b506155f987828801615556565b95989497509550505050565b60006020828403121561561757600080fd5b813580600f0b811461364557600080fd5b60006020828403121561563a57600080fd5b5035919050565b6000806040838503121561565457600080fd5b823561565f8161507b565b91506020830135600881900b811461552757600080fd5b6000806040838503121561568957600080fd5b82356001600160401b0381111561569f57600080fd5b6153858582860161547d565b60a0815260006156be60a0830188615394565b90508560208301528460408301528360608301528260808301529695505050505050565b6000602082840312156156f457600080fd5b81356001600160401b0381111561570a57600080fd5b61367484828501615172565b6000806020838503121561572957600080fd5b82356001600160401b0381111561573f57600080fd5b61574b85828601615556565b90969095509350505050565b60ff8116811461466457600080fd5b600080600080600080600060e0888a03121561578157600080fd5b873561578c8161507b565b9650602088013561579c8161507b565b9550604088013594506060880135935060808801356157ba81615757565b9699959850939692959460a0840135945060c09093013592915050565b600080600080608085870312156157ed57600080fd5b84356157f88161507b565b935060208501359250604085013561580f8161507b565b9396929550929360600135925050565b600181811c9082168061583357607f821691505b60208210810361549057634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820180821115610c2257610c22615869565b6000600182016158a4576158a4615869565b5060010190565b81810381811115610c2257610c22615869565b6000808335601e198436030181126158d557600080fd5b8301803591506001600160401b038211156158ef57600080fd5b6020019150600581901b36038213156142e057600080fd5b6000610c22368361525a565b60006020828403121561592557600080fd5b813561364581615241565b8082028115828204841417610c2257610c22615869565b634e487b7160e01b600052601260045260246000fd5b60008261596c5761596c615947565b500490565b60006020828403121561598357600080fd5b6136458261513b565b60006020828403121561599e57600080fd5b81516136458161507b565b6000602082840312156159bb57600080fd5b815161364581615757565b6000600160ff1b82016159db576159db615869565b5060000390565b6000602082840312156159f457600080fd5b815161364581615241565b60006101008201905060018060a01b0380851683526001600160481b03845116602084015280602085015116604084015250604083015160080b606083015260ff606084015116608083015260ff60808401511660a083015260a0830151615a7260c08401826001600160a01b03169052565b5060c083015180151560e0840152509392505050565b600060208284031215615a9a57600080fd5b5051919050565b600181815b80851115615adc578160001904821115615ac257615ac2615869565b80851615615acf57918102915b93841c9390800290615aa6565b509250929050565b600082615af357506001610c22565b81615b0057506000610c22565b8160018114615b165760028114615b2057615b3c565b6001915050610c22565b60ff841115615b3157615b31615869565b50506001821b610c22565b5060208310610133831016604e8410600b8410161715615b5f575081810a610c22565b615b698383615aa1565b8060001904821115615b7d57615b7d615869565b029392505050565b600061364560ff841683615ae4565b60006001600160481b0380841680615bae57615bae615947565b92169190910492915050565b6001600160481b03818116838216019080821115615bda57615bda615869565b5092915050565b634e487b7160e01b600052603160045260246000fd5b8181036000831280158383131683831282161715615bda57615bda615869565b6020808252825182820181905260009190848201906040850190845b81811015615c585783516001600160a01b031683529284019291840191600101615c33565b50909695505050505050565b600081518084526020808501945080840160005b8381101561540257815187529582019590820190600101615c78565b6001600160a01b03878116825260a06020808401829052908301879052600091889160c08501845b8a811015615ce3578435615ccf8161507b565b841682529382019390820190600101615cbc565b508581036040870152615cf6818a615c64565b93505050508281036060840152615d0d8186615c64565b915050826080830152979650505050505050565b600080835481600182811c915080831680615d3d57607f831692505b60208084108203615d5c57634e487b7160e01b86526022600452602486fd5b818015615d705760018114615d8557615db2565b60ff1986168952841515850289019650615db2565b60008a81526020902060005b86811015615daa5781548b820152908501908301615d91565b505084890196505b509498975050505050505050565b80820260008212600160ff1b84141615615ddc57615ddc615869565b8181058314821517610c2257610c22615869565b600082615dff57615dff615947565b600160ff1b821460001984141615615e1957615e19615869565b500590565b8082018281126000831280158216821582161715615e3e57615e3e615869565b505092915050565b60008251615e58818460208701615024565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122068e9ddcfbd3c43085683c87112d80438c0cb8e8db0d4c7ebf93715cd6bbf957f64736f6c63430008130033

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

00000000000000000000000094194de310b99d3c8a5b8c0768cfce7aef81d9be0000000000000000000000009b122361e8708be33b785e44fce4d6ca86ab6c5a000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e100000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002386f26fc10000

-----Decoded View---------------
Arg [0] : _relayer (address): 0x94194DE310b99d3c8a5b8C0768cFCE7Aef81D9BE
Arg [1] : _oracleModule (address): 0x9B122361E8708Be33B785e44FcE4d6ca86AB6C5a
Arg [2] : _governanceModule (address): 0xc6F50903a058f3807111619bD4B24cA64b8239E1
Arg [3] : _maxAumDeviationAllowed (uint16): 200
Arg [4] : _taxFactor (uint72): 0
Arg [5] : _managementFee (uint72): 10000000000000000

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 00000000000000000000000094194de310b99d3c8a5b8c0768cfce7aef81d9be
Arg [1] : 0000000000000000000000009b122361e8708be33b785e44fce4d6ca86ab6c5a
Arg [2] : 000000000000000000000000c6f50903a058f3807111619bd4b24ca64b8239e1
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000c8
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 000000000000000000000000000000000000000000000000002386f26fc10000


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.