ETH Price: $3,455.53 (+1.20%)
Gas: 22 Gwei

Contract

0x87Cc45fFF5c0933bb6aF6bAe7Fc013b7eC7df2Ee
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

TokenTracker

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Approve203249672024-07-17 8:10:596 hrs ago1721203859IN
Fyde: TRSY Token
0 ETH0.000280569.63123348
Approve203249452024-07-17 8:06:356 hrs ago1721203595IN
Fyde: TRSY Token
0 ETH0.000423789.17146388
Approve203239752024-07-17 4:51:599 hrs ago1721191919IN
Fyde: TRSY Token
0 ETH0.000187.4312339
Approve203239562024-07-17 4:48:119 hrs ago1721191691IN
Fyde: TRSY Token
0 ETH0.000320636.93540151
Approve203221812024-07-16 22:52:1115 hrs ago1721170331IN
Fyde: TRSY Token
0 ETH0.000216164.67575281
Approve203194142024-07-16 13:36:5924 hrs ago1721137019IN
Fyde: TRSY Token
0 ETH0.000210138.67490012
Approve203189212024-07-16 11:58:1126 hrs ago1721131091IN
Fyde: TRSY Token
0 ETH0.000446269.65285203
Approve203186732024-07-16 11:08:3527 hrs ago1721128115IN
Fyde: TRSY Token
0 ETH0.000356647.71444327
Approve203186452024-07-16 11:02:5927 hrs ago1721127779IN
Fyde: TRSY Token
0 ETH0.000283066.1275421
Transfer203185842024-07-16 10:50:3527 hrs ago1721127035IN
Fyde: TRSY Token
0 ETH0.000169894.96106752
Approve203184282024-07-16 10:19:1128 hrs ago1721125151IN
Fyde: TRSY Token
0 ETH0.000262575.67962697
Approve203178552024-07-16 8:23:5930 hrs ago1721118239IN
Fyde: TRSY Token
0 ETH0.000205048.46496489
Approve203173092024-07-16 6:34:1131 hrs ago1721111651IN
Fyde: TRSY Token
0 ETH0.000188354.07416379
Approve203166552024-07-16 4:22:5934 hrs ago1721103779IN
Fyde: TRSY Token
0 ETH0.000228294.94062111
Approve203142932024-07-15 20:27:3542 hrs ago1721075255IN
Fyde: TRSY Token
0 ETH0.0007278715.74431676
Approve203141332024-07-15 19:55:1142 hrs ago1721073311IN
Fyde: TRSY Token
0 ETH0.0004949116.98914855
Approve203132222024-07-15 16:51:5945 hrs ago1721062319IN
Fyde: TRSY Token
0 ETH0.0014173630.65821888
Approve203120022024-07-15 12:46:232 days ago1721047583IN
Fyde: TRSY Token
0 ETH0.000416169.00190347
Approve203107832024-07-15 8:41:112 days ago1721032871IN
Fyde: TRSY Token
0 ETH0.000230324.98207602
Approve203107722024-07-15 8:38:592 days ago1721032739IN
Fyde: TRSY Token
0 ETH0.000228434.94114176
Approve203102022024-07-15 6:44:232 days ago1721025863IN
Fyde: TRSY Token
0 ETH0.000100363.44544925
Approve203101762024-07-15 6:39:112 days ago1721025551IN
Fyde: TRSY Token
0 ETH0.000092533.51608156
Approve203101582024-07-15 6:35:352 days ago1721025335IN
Fyde: TRSY Token
0 ETH0.000141063.05205806
Approve203065532024-07-14 18:31:592 days ago1720981919IN
Fyde: TRSY Token
0 ETH0.000290116.27543492
Approve203048872024-07-14 12:57:233 days ago1720961843IN
Fyde: TRSY Token
0 ETH0.000129442.79988732
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
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.

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Chain Token Portfolio % Price Amount Value
ETH16.14%$0.1390361,429,514.2147$198,753.94
ETH8.69%$0.0528712,023,158.8777$106,966.43
ETH6.15%$3,452.7121.9228$75,693.02
ETH6.14%$4,062.0918.6213$75,641.41
ETH5.09%$3,873.7416.182$62,685.05
ETH4.79%$0.0197832,978,334.8685$58,920.91
ETH3.62%$1.9722,642.6585$44,606.04
ETH3.61%$3.4912,722.7939$44,402.55
ETH3.41%$0.0000123,504,867,973.3183$41,953.27
ETH3.26%$0.54847773,139.3586$40,115.26
ETH3.09%$7.275,240.4005$38,097.71
ETH3.09%$0.306735123,827.043$37,982.09
ETH3.02%$4.628,044.691$37,166.47
ETH2.96%$14.382,536.5911$36,476.18
ETH2.96%$1.133,272.9411$36,433.87
ETH2.82%$2,918.3311.8949$34,713.14
ETH2.55%$0.0056535,542,491.9042$31,333.15
ETH2.48%$0.0179631,702,965.2958$30,589.94
ETH2.33%$0.049103584,892.5017$28,720.08
ETH2.13%$321.4281.6321$26,238.2
ETH2.02%$124,842.2646$24,842.26
ETH1.89%$0.214456108,564.9292$23,282.4
ETH1.89%$2.1710,700.1516$23,219.33
ETH1.81%$6.793,276.0367$22,244.29
ETH1.61%$0.013941,421,883.9678$19,821.32
ETH1.41%$99.43174.942$17,394.15
ETH0.75%$1.18,446.7718$9,257.66
ETH0.12%$0.4732213,092.0982$1,463.25
ETH0.06%$9.2778.5994$728.62
ETH0.03%$2.42171.9523$416.12
ETH0.03%$0.1013413,592.1077$364.03
ETH0.03%$8.1537.9283$309.12
ETH0.01%$65,0110.00228069$148.27
ETH<0.01%$0.99903762.8567$62.8
ETH<0.01%$1.6219.8917$32.22
ETH<0.01%$0.291707105.3462$30.73
ETH<0.01%$110.6546$10.67
ETH<0.01%$0.9999815.8709$5.87
ETH<0.01%$0.08449550.8714$4.3
ETH<0.01%$0.9993313.0768$3.07
ETH<0.01%$18.360.1334$2.45
ETH<0.01%$0.7819450.9333$0.7297
Loading...
Loading
[ Download: CSV Export  ]

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