Contract

0x5f15ece3A096EefF99d786C771C2e3433255e4fB

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
4343472024-12-15 7:52:1715 days ago1734249137  Contract Creation0 S
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FluidVaultLiquidationResolver

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
paris EvmVersion
File 1 of 10 : main.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { Variables } from "./variables.sol";
import { Structs } from "./structs.sol";
import { FluidProtocolTypes } from "../../../libraries/fluidProtocolTypes.sol";
import { Structs as VaultResolverStructs } from "../vault/structs.sol";
import { IFluidVaultResolver } from "../vault/iVaultResolver.sol";
import { IFluidVaultT1 } from "../../../protocols/vault/interfaces/iVaultT1.sol";

/// @notice Resolver contract that helps in finding available token (liquidation) swaps available in Fluid VaultT1s.
/// @dev    Note that on the same protocol, if "withAbsorb = true" is executed, this also consumes the swap
///         that would be on the same protocol with "withAbsorb = false". So the total available swap amount
///         at a protocol if both a swap with and without absorb is available is not `with inAmt + without inAmt`
///         but rather `with inAmt`.
///         Sometimes with absorb can provide better swaps, sometimes without absorb can provide better swaps.
///         But available liquidity for "withAbsorb" amounts will always be >= without absorb amounts.
/// @dev    The "Raw" methods return both the with and without absorb swaps for the same Fluid Vault, the non-"Raw"
///         methods automatically filter by the better ratio swap. For same cases a better optimization of ratios
///         is possible with custom logic based on the "Raw" methods, see details in comments.
/// @dev    for native token, send 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.
/// @dev    returned swaps Struct can be fed into `getSwapTx` to prepare the tx that executes the swaps.
/// @dev    non-view methods in this contract are expected to be called with callStatic,
///         although they would anyway not do any actual state changes.
contract FluidVaultLiquidationResolver is Variables, Structs {
    /// @notice thrown if an input param address is zero
    error FluidVaultLiquidationsResolver__AddressZero();
    /// @notice thrown if an invalid param is given to a method
    error FluidVaultLiquidationsResolver__InvalidParams();

    /// @notice constructor sets the immutable vault resolver address
    constructor(IFluidVaultResolver vaultResolver_) Variables(vaultResolver_) {
        if (address(vaultResolver_) == address(0)) {
            revert FluidVaultLiquidationsResolver__AddressZero();
        }
    }

    /// @notice returns all available token swap paths
    function getAllSwapPaths() public view returns (SwapPath[] memory paths_) {
        address[] memory vaultAddresses_ = _getVaultT1s();
        paths_ = new SwapPath[](vaultAddresses_.length);

        address borrowToken_;
        address supplyToken_;
        for (uint256 i; i < vaultAddresses_.length; ++i) {
            (borrowToken_, supplyToken_) = _getVaultTokens(vaultAddresses_[i]);
            paths_[i] = SwapPath({ protocol: vaultAddresses_[i], tokenIn: borrowToken_, tokenOut: supplyToken_ });
        }
    }

    /// @notice returns all swap paths for a certain `tokenIn_` swapped to a `tokenOut_`.
    ///         returns empty array if no swap path is available for a given pair.
    function getSwapPaths(address tokenIn_, address tokenOut_) public view returns (SwapPath[] memory paths_) {
        address[] memory vaultAddresses_ = _getVaultT1s();

        uint256 foundVaultsCount_;
        address[] memory foundVaults_ = new address[](vaultAddresses_.length);

        address borrowToken_;
        address supplyToken_;
        for (uint256 i; i < vaultAddresses_.length; ++i) {
            (borrowToken_, supplyToken_) = _getVaultTokens(vaultAddresses_[i]);

            if (borrowToken_ == tokenIn_ && supplyToken_ == tokenOut_) {
                foundVaults_[foundVaultsCount_] = vaultAddresses_[i];
                ++foundVaultsCount_;
            }
        }

        paths_ = new SwapPath[](foundVaultsCount_);
        for (uint256 i; i < foundVaultsCount_; ++i) {
            paths_[i] = SwapPath({ protocol: foundVaults_[i], tokenIn: tokenIn_, tokenOut: tokenOut_ });
        }
    }

    /// @notice returns all available swap paths for any `tokensIn_` to any `tokensOut_`.
    function getAnySwapPaths(
        address[] calldata tokensIn_,
        address[] calldata tokensOut_
    ) public view returns (SwapPath[] memory paths_) {
        SwapPath[] memory maxPaths_ = new SwapPath[](tokensIn_.length * tokensOut_.length);

        address[] memory vaultAddresses_ = _getVaultT1s();

        uint256 matches_;

        address borrowToken_;
        address supplyToken_;
        unchecked {
            for (uint256 vi; vi < vaultAddresses_.length; ++vi) {
                (borrowToken_, supplyToken_) = _getVaultTokens(vaultAddresses_[vi]);

                // for each vault, iterate over all possible input params token combinations
                for (uint256 i; i < tokensIn_.length; ++i) {
                    for (uint256 j; j < tokensOut_.length; ++j) {
                        if (borrowToken_ == tokensIn_[i] && supplyToken_ == tokensOut_[j]) {
                            maxPaths_[matches_] = SwapPath({
                                protocol: vaultAddresses_[vi],
                                tokenIn: borrowToken_,
                                tokenOut: supplyToken_
                            });
                            ++matches_;
                        }
                    }
                }
            }

            paths_ = new SwapPath[](matches_);
            for (uint256 i; i < matches_; ++i) {
                paths_[i] = maxPaths_[i];
            }
        }
    }

    /// @notice returns the swap data for with and without absorb for a Fluid `vault_`.
    function getVaultSwapData(
        address vault_
    ) public returns (SwapData memory withoutAbsorb_, SwapData memory withAbsorb_) {
        VaultResolverStructs.LiquidationStruct memory liquidationData_ = VAULT_RESOLVER.getVaultLiquidation(vault_, 0);

        withoutAbsorb_ = SwapData({
            inAmt: liquidationData_.inAmt,
            outAmt: liquidationData_.outAmt,
            withAbsorb: false,
            ratio: _calcRatio(liquidationData_.inAmt, liquidationData_.outAmt)
        });

        withAbsorb_ = SwapData({
            inAmt: liquidationData_.inAmtWithAbsorb,
            outAmt: liquidationData_.outAmtWithAbsorb,
            withAbsorb: true,
            ratio: _calcRatio(liquidationData_.inAmtWithAbsorb, liquidationData_.outAmtWithAbsorb)
        });
    }

    /// @notice returns the swap data for with and without absorb for multiple Fluid `vaults_`.
    function getVaultsSwapData(
        address[] memory vaults_
    ) public returns (SwapData[] memory withoutAbsorb_, SwapData[] memory withAbsorb_) {
        withoutAbsorb_ = new SwapData[](vaults_.length);
        withAbsorb_ = new SwapData[](vaults_.length);
        for (uint256 i; i < vaults_.length; ++i) {
            (withoutAbsorb_[i], withAbsorb_[i]) = getVaultSwapData(vaults_[i]);
        }
    }

    /// @notice returns the swap data for with and without absorb for all Fluid vaults.
    function getAllVaultsSwapData() public returns (SwapData[] memory withoutAbsorb_, SwapData[] memory withAbsorb_) {
        return getVaultsSwapData(_getVaultT1s());
    }

    /// @notice returns the available swap amounts at a certain `protocol_`. Only returns non-zero swaps.
    ///         For vault protocol considering both a swap that uses liquidation with absorb and without absorb.
    function getSwapForProtocol(address protocol_) public returns (Swap memory swap_) {
        if (protocol_ == address(0)) {
            return swap_;
        }

        (address borrowToken_, address supplyToken_) = _getVaultTokens(protocol_);
        (SwapData memory withoutAbsorb_, SwapData memory withAbsorb_) = getVaultSwapData(protocol_);
        return
            Swap({
                path: SwapPath({ protocol: protocol_, tokenIn: borrowToken_, tokenOut: supplyToken_ }),
                data: _getBetterRatioSwapData(withoutAbsorb_, withAbsorb_)
            });
    }

    /// @notice returns all available `swaps_` for multiple Fluid `vaults_` raw. Only returns non-zero swaps.
    ///         includes all swaps unfiltered, e.g. with absorb and without absorb swaps are present for the same vault.
    function getVaultsSwapRaw(address[] memory vaults_) public returns (Swap[] memory swaps_) {
        unchecked {
            uint256 nonZeroSwaps_;
            Swap[] memory allSwaps_ = new Swap[](vaults_.length * 2);

            SwapData memory withoutAbsorb_;
            SwapData memory withAbsorb_;
            address borrowToken_;
            address supplyToken_;
            for (uint256 i; i < vaults_.length; ++i) {
                (withoutAbsorb_, withAbsorb_) = getVaultSwapData(vaults_[i]);
                if (withAbsorb_.inAmt == 0) {
                    // if with absorb is 0, then without absorb can only be 0 too
                    continue;
                }
                ++nonZeroSwaps_;
                if (withAbsorb_.inAmt == withoutAbsorb_.inAmt) {
                    // with absorb has the same liquidity as without absorb.
                    // running liquidate() with absorb in that case only costs extra gas. return only without absorb swap
                    withAbsorb_.inAmt = 0;
                } else if (withoutAbsorb_.inAmt > 0) {
                    // both with and without absorb swaps
                    ++nonZeroSwaps_;
                }

                (borrowToken_, supplyToken_) = _getVaultTokens(vaults_[i]);

                allSwaps_[i * 2] = Swap({
                    path: SwapPath({ protocol: vaults_[i], tokenIn: borrowToken_, tokenOut: supplyToken_ }),
                    data: withoutAbsorb_
                });
                allSwaps_[i * 2 + 1] = Swap({
                    path: SwapPath({ protocol: vaults_[i], tokenIn: borrowToken_, tokenOut: supplyToken_ }),
                    data: withAbsorb_
                });
            }

            return _getNonZeroSwaps(allSwaps_, nonZeroSwaps_);
        }
    }

    /// @notice returns all available `swaps_` for all Fluid vaults raw. Only returns non-zero swaps.
    ///         includes all swaps unfiltered, e.g. with absorb and without absorb swaps are present for the same vault.
    function getAllVaultsSwapRaw() public returns (Swap[] memory swaps_) {
        return getVaultsSwapRaw(_getVaultT1s());
    }

    /// @notice returns all the available `swaps_` for certain swap `paths_`. Only returns non-zero swaps.
    ///         includes all swaps unfiltered, e.g. with absorb and without absorb swaps are present for the same vault.
    function getSwapsForPathsRaw(SwapPath[] memory paths_) public returns (Swap[] memory swaps_) {
        unchecked {
            Swap[] memory allSwaps_ = new Swap[](paths_.length * 2);

            uint256 nonZeroSwaps_;
            SwapData memory withoutAbsorb_;
            SwapData memory withAbsorb_;
            for (uint256 i; i < paths_.length; ++i) {
                (withoutAbsorb_, withAbsorb_) = getVaultSwapData(paths_[i].protocol);

                if (withAbsorb_.inAmt == 0) {
                    // if with absorb is 0, then without absorb can only be 0 too
                    continue;
                }
                ++nonZeroSwaps_;
                if (withAbsorb_.inAmt == withoutAbsorb_.inAmt) {
                    // with absorb has the same liquidity as without absorb.
                    // running liquidate() with absorb in that case only costs extra gas. return only without absorb swap
                    withAbsorb_.inAmt = 0;
                } else if (withoutAbsorb_.inAmt > 0) {
                    // both with and without absorb swaps
                    ++nonZeroSwaps_;
                }

                allSwaps_[i * 2] = Swap({ path: paths_[i], data: withoutAbsorb_ });

                allSwaps_[i * 2 + 1] = Swap({ path: paths_[i], data: withAbsorb_ });
            }

            swaps_ = new Swap[](nonZeroSwaps_);
            uint256 index_;
            for (uint256 i; i < allSwaps_.length; ++i) {
                if (allSwaps_[i].data.inAmt > 0) {
                    swaps_[index_] = allSwaps_[i];
                    ++index_;
                }
            }
        }
    }

    /// @notice finds all available `swaps_` for `tokenIn_` to `tokenOut_`.
    ///         includes all swaps unfiltered, e.g. with absorb and without absorb swaps are present for the same vault.
    function getSwapsRaw(address tokenIn_, address tokenOut_) public returns (Swap[] memory swaps_) {
        return getSwapsForPathsRaw(getSwapPaths(tokenIn_, tokenOut_));
    }

    /// @notice finds all available `swaps_` for any `tokensIn_` to any `tokesnOut_`.
    ///         Token pairs that are not available or where available swap amounts are zero
    ///         will not be present in the returned `swaps_` array.
    ///         includes all swaps unfiltered, e.g. with absorb and without absorb swaps are present for the same vault.
    function getAnySwapsRaw(
        address[] calldata tokensIn_,
        address[] calldata tokensOut_
    ) public returns (Swap[] memory swaps_) {
        return getSwapsForPathsRaw(getAnySwapPaths(tokensIn_, tokensOut_));
    }

    /// @notice returns all available `swaps_` for multiple Fluid `vaults_`. Only returns non-zero swaps.
    ///         returns only either the with absorb swap or without absorb swap for each vault, whichever has the
    ///         better ratio.
    function getVaultsSwap(address[] memory vaults_) public returns (Swap[] memory swaps_) {
        unchecked {
            uint256 nonZeroSwaps_;
            Swap[] memory allSwaps_ = new Swap[](vaults_.length);

            SwapData memory withoutAbsorb_;
            SwapData memory withAbsorb_;
            Swap memory swap_;
            for (uint256 i; i < vaults_.length; ++i) {
                (withoutAbsorb_, withAbsorb_) = getVaultSwapData(vaults_[i]);
                swap_ = Swap({
                    path: SwapPath({ protocol: vaults_[i], tokenIn: address(0), tokenOut: address(0) }),
                    data: _getBetterRatioSwapData(withoutAbsorb_, withAbsorb_)
                });

                if (swap_.data.inAmt == 0) {
                    // no swap available on this vault
                    continue;
                }

                ++nonZeroSwaps_;

                (swap_.path.tokenIn, swap_.path.tokenOut) = _getVaultTokens(vaults_[i]);

                allSwaps_[i] = swap_;
            }

            return _getNonZeroSwaps(allSwaps_, nonZeroSwaps_);
        }
    }

    /// @notice returns all available `swaps_` for all Fluid vaults. Only returns non-zero swaps.
    ///         returns only either the with absorb swap or without absorb swap for each vault, whichever has the
    ///         better ratio.
    function getAllVaultsSwap() public returns (Swap[] memory swaps_) {
        return getVaultsSwap(_getVaultT1s());
    }

    /// @notice returns all the available `swaps_` for certain swap `paths_`. Only returns non-zero swaps.
    ///         returns only either the with absorb swap or without absorb swap for each vault, whichever has the
    ///         better ratio.
    function getSwapsForPaths(SwapPath[] memory paths_) public returns (Swap[] memory swaps_) {
        unchecked {
            Swap[] memory allSwaps_ = new Swap[](paths_.length);

            uint256 nonZeroSwaps_;
            Swap memory swap_;
            SwapData memory withoutAbsorb_;
            SwapData memory withAbsorb_;
            for (uint256 i; i < paths_.length; ++i) {
                (withoutAbsorb_, withAbsorb_) = getVaultSwapData(paths_[i].protocol);
                swap_ = Swap({ path: paths_[i], data: _getBetterRatioSwapData(withoutAbsorb_, withAbsorb_) });

                if (swap_.data.inAmt == 0) {
                    // no swap available on this vault
                    continue;
                }

                ++nonZeroSwaps_;

                allSwaps_[i] = swap_;
            }

            return _getNonZeroSwaps(allSwaps_, nonZeroSwaps_);
        }
    }

    /// @notice finds all available `swaps_` for `tokenIn_` to `tokenOut_`.
    ///         returns only either the with absorb swap or without absorb swap for each vault, whichever has the
    ///         better ratio.
    function getSwaps(address tokenIn_, address tokenOut_) public returns (Swap[] memory swaps_) {
        return getSwapsForPaths(getSwapPaths(tokenIn_, tokenOut_));
    }

    /// @notice finds all available `swaps_` for any `tokensIn_` to any `tokesnOut_`.
    ///         Token pairs that are not available or where available swap amounts are zero
    ///         will not be present in the returned `swaps_` array.
    ///         returns only either the with absorb swap or without absorb swap for each vault, whichever has the
    ///         better ratio.
    function getAnySwaps(
        address[] calldata tokensIn_,
        address[] calldata tokensOut_
    ) public returns (Swap[] memory swaps_) {
        return getSwapsForPaths(getAnySwapPaths(tokensIn_, tokensOut_));
    }

    /// @notice returns the calldata to execute a swap as returned by the other methods in this contract.
    ///         `swap_.data.inAmt` must come from msg.sender, `swap_.data.outAmt` goes to `receiver_`. If the input token
    ///         is the native token, msg.value must be sent along when triggering the actual call with the returned calldata
    ///         which should be `swap_.data.inAmt`.
    /// @param swap_ Swap struct as returned by other methods
    /// @param receiver_ receiver address that the output token is sent to
    /// @param slippage_ maximum allowed slippage for the expected output token amount. Reverts iIf received token out
    ///                  amount is lower than this. in 1e4 percentage, e.g. 1% = 10000, 0.3% = 3000, 0.01% = 100, 0.0001% = 1.
    /// @return target_ target address where `calldata_` must be executed
    /// @return calldata_ the calldata that can be used to trigger the liquidation call, resulting in the desired swap.
    function getSwapTx(
        Swap calldata swap_,
        address receiver_,
        uint256 slippage_
    ) public pure returns (address target_, bytes memory calldata_) {
        if (swap_.path.protocol == address(0) || receiver_ == address(0)) {
            revert FluidVaultLiquidationsResolver__AddressZero();
        }
        if (slippage_ >= 1e6 || swap_.data.inAmt == 0 || swap_.data.outAmt == 0) {
            revert FluidVaultLiquidationsResolver__InvalidParams();
        }

        uint256 colPerUnitDebt_ = (swap_.data.outAmt * 1e18) / swap_.data.inAmt;
        colPerUnitDebt_ = (colPerUnitDebt_ * (1e6 - slippage_)) / 1e6; // e.g. 50 * 99% / 100% = 49.5

        calldata_ = abi.encodeWithSelector(
            IFluidVaultT1(swap_.path.protocol).liquidate.selector,
            swap_.data.inAmt,
            colPerUnitDebt_,
            receiver_,
            swap_.data.withAbsorb
        );
        target_ = swap_.path.protocol;
    }

    /// @notice returns the same data as `getSwapTx` for an array of input `swaps_` at once.
    function getSwapTxs(
        Swap[] calldata swaps_,
        address receiver_,
        uint256 slippage_
    ) public pure returns (address[] memory targets_, bytes[] memory calldatas_) {
        targets_ = new address[](swaps_.length);
        calldatas_ = new bytes[](swaps_.length);
        for (uint256 i; i < swaps_.length; ++i) {
            (targets_[i], calldatas_[i]) = getSwapTx(swaps_[i], receiver_, slippage_);
        }
    }

    /// @notice finds all swaps from `tokenIn_` to `tokenOut_` for an exact input amount `inAmt_`.
    ///         filters the available swaps and sorts them by ratio, so the returned swaps are the best available
    ///         swaps to reach the target `inAmt_`.
    ///         If the full available amount is less than the target `inAmt_`, the available amount is returned as `actualInAmt_`.
    /// @dev The only cases that are currently not best possible optimized for are when the ratio for withoutAbsorb is better
    /// but the target swap amount is more than the available without absorb liquidity. For this, currently the available
    /// withAbsorb liquidity is consumed first before tapping into the better ratio withoutAbsorb liquidity.
    /// The optimized version would be to split the tx into two swaps, first executing liquidate() with absorb = false
    /// to fully swap all the withoutAbsorb liquidity, and then in the second tx run with absorb = true to fill the missing
    /// amount up to the target amount with the worse ratio with absorb liquidity.
    /// @param tokenIn_ input token
    /// @param tokenOut_ output token
    /// @param inAmt_ exact input token amount that should be swapped to output token
    /// @return swaps_ swaps to reach the target amount, sorted by ratio in descending order
    ///         (higher ratio = better rate). Best ratio swap will be at pos 0, second best at pos 1 and so on.
    /// @return actualInAmt_ actual input token amount. Can be less than inAmt_ if all available swaps can not cover
    ///                      the target amount.
    /// @return outAmt_ output token amount received for `actualInAmt_`
    function exactInput(
        address tokenIn_,
        address tokenOut_,
        uint256 inAmt_
    ) public returns (Swap[] memory swaps_, uint256 actualInAmt_, uint256 outAmt_) {
        return filterToTargetInAmt(getSwapsRaw(tokenIn_, tokenOut_), inAmt_);
    }

    /// @notice finds all swaps from `tokenIn_` to `tokenOut_` for an APPROXIMATE output amount `outAmt_`.
    ///         filters the available swaps and sorts them by ratio, so the returned swaps are the best available
    ///         swaps to reach the target `outAmt_`.
    ///         If the full available amount is less than the target `outAmt_`, the available amount is returned as `actualOutAmt_`.
    ///         IMPORTANT: guaranteed exact output swaps are not possible with Fluid, this method only aims to
    ///         approximately estimate the required input amounts to reach a certain output amount. This
    ///         will change until execution and should be controlled with a maximum slippage.
    ///         Recommended to use exact input methods instead.
    /// @dev The only cases that are currently not best possible optimized for are when the ratio for withoutAbsorb is better
    /// but the target swap amount is more than the available without absorb liquidity. For this currently the available
    /// withAbsorb liquidity is consumed first before tapping into the better ratio withoutAbsorb liquidity.
    /// The optimized version would be to split the tx into two swaps, first executing liquidate() with absorb = false
    /// to fully swap all the withoutAbsorb liquidity, and then in the second tx run with absorb = true to fill the missing
    /// amount up to the target amount with the worse ratio with absorb liquidity.
    /// @param tokenIn_ input token
    /// @param tokenOut_ output token
    /// @param outAmt_ exact output token amount that should be swapped to from input token
    /// @return swaps_ swaps to reach the target amount, sorted by ratio in descending order
    ///         (higher ratio = better rate). Best ratio swap will be at pos 0, second best at pos 1 and so on.
    /// @return inAmt_ input token amount needed to receive `actualOutAmt_`
    /// @return approxOutAmt_ approximate output token amount. Can be less than `outAmt_` if all available swaps can not cover
    ///                       the target amount.
    function approxOutput(
        address tokenIn_,
        address tokenOut_,
        uint256 outAmt_
    ) public returns (Swap[] memory swaps_, uint256 inAmt_, uint256 approxOutAmt_) {
        return filterToApproxOutAmt(getSwapsRaw(tokenIn_, tokenOut_), outAmt_);
    }

    /// @notice filters the `swaps_` to the point where `targetInAmt_` is reached.
    ///         This is best used in combination with the "Raw" methods, as the `targetInAmt_` allows for more optimized
    ///         filtering than otherwise done with the non-"Raw" methods.
    /// @return filteredSwaps_ swaps to reach the target amount, sorted by ratio in descending order
    ///         (higher ratio = better rate). Best ratio swap will be at pos 0, second best at pos 1 and so on.
    /// @return actualInAmt_ actual input amount. Can be less than targetInAmt_ if all available swaps can not cover
    ///                      the target amount.
    /// @return approxOutAmt_ actual estimated output amount.
    function filterToTargetInAmt(
        Swap[] memory swaps_,
        uint256 targetInAmt_
    ) public returns (Swap[] memory filteredSwaps_, uint256 actualInAmt_, uint256 approxOutAmt_) {
        return _filterToTarget(swaps_, targetInAmt_, type(uint256).max);
    }

    /// @notice filters the `swaps_` to the point where APPROXIMATELY `targetOutAmt_` is reached.
    ///         IMPORTANT: guaranteed exact output swaps are not possible with Fluid, this method only aims to
    ///         approximately estimate the required input amounts to reach a certain output amount. This
    ///         will change until execution and should be controlled with a maximum slippage.
    ///         Recommended to use exact input methods instead.
    ///         This is best used in combination with the "Raw" methods, as the `targetInAmt_` allows for more optimized
    ///         filtering than otherwise done with the non-"Raw" methods.
    /// @return filteredSwaps_ swaps to reach the target amount, sorted by ratio in descending order
    ///         (higher ratio = better rate). Best ratio swap will be at pos 0, second best at pos 1 and so on.
    /// @return actualInAmt_ actual input amount.
    /// @return approxOutAmt_ APPROXIMATE actual output amount. Can be less than targetOutAmt_ if all available swaps
    ///                      can not cover the target amount.
    function filterToApproxOutAmt(
        Swap[] memory swaps_,
        uint256 targetApproxOutAmt_
    ) public returns (Swap[] memory filteredSwaps_, uint256 actualInAmt_, uint256 approxOutAmt_) {
        return _filterToTarget(swaps_, type(uint256).max, targetApproxOutAmt_);
    }

    /// @dev filters the `swaps_` to the point where either `targetInAmt_` or `targetOutAmt_` is reached.
    ///         To filter only by in or only by out amount, send `type(uint256).max` for the other param.
    /// @return filteredSwaps_ swaps to reach the target amount, sorted by ratio in descending order
    ///         (higher ratio = better rate). Best ratio swap will be at pos 0, second best at pos 1 and so on.
    /// @return actualInAmt_ actual input amount. Can be less than targetInAmt_ if all available swaps can not cover
    ///                      the target amount.
    /// @return actualOutAmt_ actual output amount. Can be less than targetOutAmt_ if all available swaps can not cover
    ///                      the target amount.
    function _filterToTarget(
        Swap[] memory swaps_,
        uint256 targetInAmt_,
        uint256 targetOutAmt_
    ) internal returns (Swap[] memory filteredSwaps_, uint256 actualInAmt_, uint256 actualOutAmt_) {
        swaps_ = _sortByRatio(swaps_);
        (filteredSwaps_, actualInAmt_, actualOutAmt_) = _filterSwapsUntilTarget(swaps_, targetInAmt_, targetOutAmt_);

        if (actualInAmt_ > targetInAmt_ || actualOutAmt_ > targetOutAmt_) {
            // reduce last swap in amt to match target in amt
            uint256 lastSwapIndex_ = filteredSwaps_.length - 1;

            uint256 missingInAmt_;
            if (actualInAmt_ > targetInAmt_) {
                // swaps_[i].data.inAmt is causing that we over reach targetInAmt_
                // so to get missing account from here until targetInAmt_, we only want
                // swaps_[i].data.inAmt minus whatever is too much (actualInAmt_ - targetInAmt_)
                missingInAmt_ = filteredSwaps_[lastSwapIndex_].data.inAmt + 1 - (actualInAmt_ - targetInAmt_);
            } else {
                // get missing in amt to use for liquidation call input param based on missing out amt and ratio
                uint256 missingOutAmt_ = filteredSwaps_[lastSwapIndex_].data.outAmt - (actualOutAmt_ - targetOutAmt_);

                // get total available liquidation and the ratios for with absorb vs without absorb
                VaultResolverStructs.LiquidationStruct memory liquidationDataAvailable_ = VAULT_RESOLVER
                    .getVaultLiquidation(filteredSwaps_[lastSwapIndex_].path.protocol, 0);

                uint256 withoutAbsorbRatio_ = _calcRatio(
                    liquidationDataAvailable_.inAmt,
                    liquidationDataAvailable_.outAmt
                );
                // calculate the ratio of the absorb only liquidity part
                uint256 absorbOnlyRatio_ = _calcRatio(
                    liquidationDataAvailable_.inAmtWithAbsorb - liquidationDataAvailable_.inAmt,
                    liquidationDataAvailable_.outAmtWithAbsorb - liquidationDataAvailable_.outAmt
                );
                if (absorbOnlyRatio_ > withoutAbsorbRatio_ || liquidationDataAvailable_.outAmt < missingOutAmt_) {
                    // with absorb has the better ratio than without absorb or without absorb can not fully cover
                    // the missing out amount. So with absorb has to be run.
                    // Note for the case liquidationDataAvailable_.outAmt < missingOutAmt_:
                    // missing in amt would ideally be a combination of the whole without absorb liquidity +
                    // some left over which has the different (worse) with absorb ratio.
                    // when running withAbsorb = true, always the whole with absorb liquidity is taken first.
                    // so to profit of the better without absorb liquidity, this would have to be turned into 2 swaps.
                    // but this might not always be better because of gas usage etc., so for simplicity we just
                    // take the whole absorb liquidity first.

                    // check if absorb only liquidity covers the missing out amount, if so then the swap ratio is already known
                    // as absorbOnlyRatio_ which can be used to derive the required inAmt
                    uint256 asborbOnlyLiquidity_ = liquidationDataAvailable_.outAmtWithAbsorb -
                        liquidationDataAvailable_.outAmt;
                    if (asborbOnlyLiquidity_ >= missingOutAmt_) {
                        missingInAmt_ = (missingOutAmt_ * 1e27) / absorbOnlyRatio_ + 1;
                    } else {
                        // missing in amt is a combination of the whole absorb liquidity + some left over
                        // which has the different without absorb ratio
                        missingInAmt_ = (asborbOnlyLiquidity_ * 1e27) / absorbOnlyRatio_ + 1;
                        missingInAmt_ += ((missingOutAmt_ - asborbOnlyLiquidity_) * 1e27) / withoutAbsorbRatio_ + 1;
                    }
                } else {
                    // without absorb has the better ratio AND missing out amount can be covered by without absorb liquidity
                    missingInAmt_ = (missingOutAmt_ * 1e27) / withoutAbsorbRatio_ + 1;
                }
            }

            VaultResolverStructs.LiquidationStruct memory liquidationData_ = VAULT_RESOLVER.getVaultLiquidation(
                filteredSwaps_[lastSwapIndex_].path.protocol,
                missingInAmt_
            );

            actualInAmt_ -= filteredSwaps_[lastSwapIndex_].data.inAmt;
            actualOutAmt_ -= filteredSwaps_[lastSwapIndex_].data.outAmt;

            if (filteredSwaps_[lastSwapIndex_].data.withAbsorb) {
                filteredSwaps_[lastSwapIndex_].data.inAmt = liquidationData_.inAmtWithAbsorb;
                filteredSwaps_[lastSwapIndex_].data.outAmt = liquidationData_.outAmtWithAbsorb;
                filteredSwaps_[lastSwapIndex_].data.ratio = _calcRatio(
                    liquidationData_.inAmtWithAbsorb,
                    liquidationData_.outAmtWithAbsorb
                );
            } else {
                filteredSwaps_[lastSwapIndex_].data.inAmt = liquidationData_.inAmt;
                filteredSwaps_[lastSwapIndex_].data.outAmt = liquidationData_.outAmt;
                filteredSwaps_[lastSwapIndex_].data.ratio = _calcRatio(liquidationData_.inAmt, liquidationData_.outAmt);
            }

            actualInAmt_ += filteredSwaps_[lastSwapIndex_].data.inAmt;
            actualOutAmt_ += filteredSwaps_[lastSwapIndex_].data.outAmt;
        }
    }

    /// @dev sorts `swaps_` by ratio descending. Higher ratio is better (getting more output for input).
    ///      Best ratio swap will be at pos 0, second best at pos 1 and so on
    function _sortByRatio(Swap[] memory swaps_) internal pure returns (Swap[] memory) {
        bool swapped_;
        Swap memory helper_;
        for (uint256 i = 1; i < swaps_.length; i++) {
            swapped_ = false;
            for (uint256 j = 0; j < swaps_.length - i; j++) {
                if (swaps_[j + 1].data.ratio > swaps_[j].data.ratio) {
                    helper_ = swaps_[j];
                    swaps_[j] = swaps_[j + 1];
                    swaps_[j + 1] = helper_;
                    swapped_ = true;
                }
            }
            if (!swapped_) {
                return swaps_;
            }
        }

        return swaps_;
    }

    /// @dev filters `swaps_` to exactly reach `targetInAmt_`. Takes into consideration to filter out any swaps
    ///      where both the withAbsorb and withoutAbsorb swap would be present for the same protocol, only
    ///      leaving the withAbsorb swap (as that includes withoutAbsorb).
    ///      Also returns the total in `sumInAmt_` and out `sumOutAmt_` amounts, which will be less than `targetInAmt_`
    ///      in the case that the target amount can not be reached even with all swaps.
    function _filterSwapsUntilTarget(
        Swap[] memory swaps_,
        uint256 targetInAmt_,
        uint256 targetOutAmt_
    ) internal returns (Swap[] memory filteredSwaps_, uint256 sumInAmt_, uint256 sumOutAmt_) {
        if (swaps_.length == 0) {
            return (swaps_, 0, 0);
        }
        uint256 filteredCount_;
        // find swaps needed until target in amt
        while (sumInAmt_ < targetInAmt_ && sumOutAmt_ < targetOutAmt_ && filteredCount_ < swaps_.length) {
            sumInAmt_ += swaps_[filteredCount_].data.inAmt;
            sumOutAmt_ += swaps_[filteredCount_].data.outAmt;
            ++filteredCount_;
        }

        // must not double count without absorb when with absorb is already present
        // until filteredCount, for any protocol where with absorb is present,
        // filter out the without absorb if that swap is present too.
        // if any is found then the while to find swaps until targetAmt must be run again
        // as it will be less with the filtered out element deducted.
        uint256 duplicatesCount_;
        for (uint256 i; i < filteredCount_ - 1; ++i) {
            for (uint256 j = i + 1; j < filteredCount_; ++j) {
                if (swaps_[i].path.protocol == swaps_[j].path.protocol) {
                    // same protocol present twice (with and without absorb).
                    // mark without absorb to be removed by setting the inAmt to 0
                    if (swaps_[i].data.withAbsorb) {
                        swaps_[j].data.inAmt = 0;
                    } else {
                        swaps_[i].data.inAmt = 0;
                    }
                    duplicatesCount_++;
                }
            }
        }

        if (duplicatesCount_ > 0) {
            uint256 index_;
            // filter swaps that are set to 0
            filteredSwaps_ = new Swap[](swaps_.length - duplicatesCount_);
            for (uint256 i; i < swaps_.length; ++i) {
                if (swaps_[i].data.inAmt > 0) {
                    filteredSwaps_[index_] = swaps_[i];
                    ++index_;
                }
            }

            // recursive call again to reach target amount as planned.
            return _filterSwapsUntilTarget(filteredSwaps_, targetInAmt_, targetOutAmt_);
        }

        // when clean of duplicates -> finished, return filtered swaps and total sumInAmt
        filteredSwaps_ = new Swap[](filteredCount_);
        for (uint256 i; i < filteredCount_; ++i) {
            filteredSwaps_[i] = swaps_[i];
        }
        return (filteredSwaps_, sumInAmt_, sumOutAmt_);
    }

    /// @dev gets the better swap based on ratio of with vs without absorb swap data.
    function _getBetterRatioSwapData(
        SwapData memory withoutAbsorb_,
        SwapData memory withAbsorb_
    ) internal pure returns (SwapData memory swap_) {
        if (withAbsorb_.inAmt == 0) {
            // if ratio == 0, meaning inAmt is 0, then the with absorb swap is returned.
            return withAbsorb_;
        }

        if (withAbsorb_.ratio > withoutAbsorb_.ratio) {
            // If (ratio of withAbsorb > ratio of withoutAbsorb) then always absorb should be true.
            return withAbsorb_;
        }

        if (withAbsorb_.ratio == withoutAbsorb_.ratio) {
            if (withAbsorb_.inAmt == withoutAbsorb_.inAmt) {
                // with absorb has the same liquidity as without absorb.
                // running liquidate() with absorb in that case only costs extra gas. return only without absorb swap
                return withoutAbsorb_;
            }

            // with absorb has more liquidity, but same ratio -> return with absorb
            return withAbsorb_;
        }

        // ratio of without absorb is better.
        // Note: case where with absorb has worse ratio. but it could have significant more liquidity -> will not be
        // returned here as long as there is without absorb liquidity...
        return withoutAbsorb_;
    }

    /// @dev filters `allSwaps_` to the non zero amount `swaps_`, knowing the `nonZeroSwapsCount_`
    function _getNonZeroSwaps(
        Swap[] memory allSwaps_,
        uint256 nonZeroSwapsCount_
    ) internal pure returns (Swap[] memory swaps_) {
        unchecked {
            swaps_ = new Swap[](nonZeroSwapsCount_);
            uint256 index_;
            for (uint256 i; i < allSwaps_.length; ++i) {
                if (allSwaps_[i].data.inAmt > 0) {
                    swaps_[index_] = allSwaps_[i];
                    ++index_;
                }
            }
        }
    }

    /// @dev gets the `vault_` token in (borrow token) and token out (supply token)
    function _getVaultTokens(address vault_) internal view returns (address tokenIn_, address tokenOut_) {
        IFluidVaultT1.ConstantViews memory constants_ = IFluidVaultT1(vault_).constantsView();
        return (constants_.borrowToken, constants_.supplyToken);
    }

    /// @dev returns ratio for how much outAmt_ am I getting for inAmt_. scaled by 1e27
    function _calcRatio(uint256 inAmt_, uint256 outAmt_) internal pure returns (uint256) {
        if (outAmt_ == 0) {
            return 0;
        }
        return (outAmt_ * 1e27) / inAmt_;
    }

    /// @dev returns all VaultT1 type protocols at the Fluid VaultFactory
    function _getVaultT1s() internal view returns (address[] memory) {
        return FluidProtocolTypes.filterBy(VAULT_RESOLVER.getAllVaultsAddresses(), FluidProtocolTypes.VAULT_T1_TYPE);
    }
}

File 2 of 10 : fluidProtocolTypes.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

interface IFluidProtocol {
    function TYPE() external view returns (uint256);
}

/// @notice implements helper methods to filter Fluid protocols by a certain type
library FluidProtocolTypes {
    uint256 internal constant VAULT_T1_TYPE = 10000; // VaultT1 borrow protocol type vaults
    uint256 internal constant VAULT_T2_SMART_COL_TYPE = 20000; // DEX protocol type vault
    uint256 internal constant VAULT_T3_SMART_DEBT_TYPE = 30000; // DEX protocol type vault
    uint256 internal constant VAULT_T4_SMART_COL_SMART_DEBT_TYPE = 40000; // DEX protocol type vault

    /// @dev filters input `addresses_` by protocol `type_`. Input addresses must be actual Fluid protocols, otherwise
    ///      they would be wrongly assumed to be VaultT1 even if they are not Fluid VaultT1 smart contracts.
    ///      `type_` must be a listed constant type of this library.
    ///      Example usage is to filter all vault addresses at the Vault factory by a certain type, e.g. to not include
    ///      DEX protocol type vaults.
    function filterBy(address[] memory addresses_, uint256 type_) internal view returns (address[] memory filtered_) {
        uint256 curType_;
        uint256 filteredProtocols_ = addresses_.length;
        for (uint256 i; i < addresses_.length; ) {
            try IFluidProtocol(addresses_[i]).TYPE() returns (uint256 protocolType_) {
                curType_ = protocolType_;
            } catch {
                curType_ = VAULT_T1_TYPE;
            }

            if (curType_ != type_) {
                addresses_[i] = address(0);
                --filteredProtocols_;
            }

            unchecked {
                ++i;
            }
        }

        filtered_ = new address[](filteredProtocols_);
        uint256 index_;
        unchecked {
            for (uint256 i; i < addresses_.length; ) {
                if (addresses_[i] != address(0)) {
                    filtered_[index_] = addresses_[i];
                    ++index_;
                }
                ++i;
            }
        }
    }
}

File 3 of 10 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

abstract contract Structs {
    struct AddressBool {
        address addr;
        bool value;
    }

    struct AddressUint256 {
        address addr;
        uint256 value;
    }

    /// @notice struct to set borrow rate data for version 1
    struct RateDataV1Params {
        ///
        /// @param token for rate data
        address token;
        ///
        /// @param kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100
        /// utilization below kink usually means slow increase in rate, once utilization is above kink borrow rate increases fast
        uint256 kink;
        ///
        /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100
        /// i.e. constant minimum borrow rate
        /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)
        uint256 rateAtUtilizationZero;
        ///
        /// @param rateAtUtilizationKink borrow rate when utilization is at kink. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 7% at kink then rateAtUtilizationKink would be 700
        uint256 rateAtUtilizationKink;
        ///
        /// @param rateAtUtilizationMax borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500
        uint256 rateAtUtilizationMax;
    }

    /// @notice struct to set borrow rate data for version 2
    struct RateDataV2Params {
        ///
        /// @param token for rate data
        address token;
        ///
        /// @param kink1 first kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100
        /// utilization below kink 1 usually means slow increase in rate, once utilization is above kink 1 borrow rate increases faster
        uint256 kink1;
        ///
        /// @param kink2 second kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100
        /// utilization below kink 2 usually means slow / medium increase in rate, once utilization is above kink 2 borrow rate increases fast
        uint256 kink2;
        ///
        /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100
        /// i.e. constant minimum borrow rate
        /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)
        uint256 rateAtUtilizationZero;
        ///
        /// @param rateAtUtilizationKink1 desired borrow rate when utilization is at first kink. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 7% at first kink then rateAtUtilizationKink would be 700
        uint256 rateAtUtilizationKink1;
        ///
        /// @param rateAtUtilizationKink2 desired borrow rate when utilization is at second kink. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 7% at second kink then rateAtUtilizationKink would be 1_200
        uint256 rateAtUtilizationKink2;
        ///
        /// @param rateAtUtilizationMax desired borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500
        uint256 rateAtUtilizationMax;
    }

    /// @notice struct to set token config
    struct TokenConfig {
        ///
        /// @param token address
        address token;
        ///
        /// @param fee charges on borrower's interest. in 1e2: 100% = 10_000; 1% = 100
        uint256 fee;
        ///
        /// @param threshold on when to update the storage slot. in 1e2: 100% = 10_000; 1% = 100
        uint256 threshold;
        ///
        /// @param maxUtilization maximum allowed utilization. in 1e2: 100% = 10_000; 1% = 100
        ///                       set to 100% to disable and have default limit of 100% (avoiding SLOAD).
        uint256 maxUtilization;
    }

    /// @notice struct to set user supply & withdrawal config
    struct UserSupplyConfig {
        ///
        /// @param user address
        address user;
        ///
        /// @param token address
        address token;
        ///
        /// @param mode: 0 = without interest. 1 = with interest
        uint8 mode;
        ///
        /// @param expandPercent withdrawal limit expand percent. in 1e2: 100% = 10_000; 1% = 100
        /// Also used to calculate rate at which withdrawal limit should decrease (instant).
        uint256 expandPercent;
        ///
        /// @param expandDuration withdrawal limit expand duration in seconds.
        /// used to calculate rate together with expandPercent
        uint256 expandDuration;
        ///
        /// @param baseWithdrawalLimit base limit, below this, user can withdraw the entire amount.
        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:
        /// with interest -> raw, without interest -> normal
        uint256 baseWithdrawalLimit;
    }

    /// @notice struct to set user borrow & payback config
    struct UserBorrowConfig {
        ///
        /// @param user address
        address user;
        ///
        /// @param token address
        address token;
        ///
        /// @param mode: 0 = without interest. 1 = with interest
        uint8 mode;
        ///
        /// @param expandPercent debt limit expand percent. in 1e2: 100% = 10_000; 1% = 100
        /// Also used to calculate rate at which debt limit should decrease (instant).
        uint256 expandPercent;
        ///
        /// @param expandDuration debt limit expand duration in seconds.
        /// used to calculate rate together with expandPercent
        uint256 expandDuration;
        ///
        /// @param baseDebtCeiling base borrow limit. until here, borrow limit remains as baseDebtCeiling
        /// (user can borrow until this point at once without stepped expansion). Above this, automated limit comes in place.
        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:
        /// with interest -> raw, without interest -> normal
        uint256 baseDebtCeiling;
        ///
        /// @param maxDebtCeiling max borrow ceiling, maximum amount the user can borrow.
        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:
        /// with interest -> raw, without interest -> normal
        uint256 maxDebtCeiling;
    }
}

File 4 of 10 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { Structs as AdminModuleStructs } from "../../../liquidity/adminModule/structs.sol";

abstract contract Structs {
    struct RateData {
        uint256 version;
        AdminModuleStructs.RateDataV1Params rateDataV1;
        AdminModuleStructs.RateDataV2Params rateDataV2;
    }

    struct OverallTokenData {
        uint256 borrowRate;
        uint256 supplyRate;
        uint256 fee; // revenue fee
        uint256 lastStoredUtilization;
        uint256 storageUpdateThreshold;
        uint256 lastUpdateTimestamp;
        uint256 supplyExchangePrice;
        uint256 borrowExchangePrice;
        uint256 supplyRawInterest;
        uint256 supplyInterestFree;
        uint256 borrowRawInterest;
        uint256 borrowInterestFree;
        uint256 totalSupply;
        uint256 totalBorrow;
        uint256 revenue;
        uint256 maxUtilization; // maximum allowed utilization
        RateData rateData;
    }

    // amounts are always in normal (for withInterest already multiplied with exchange price)
    struct UserSupplyData {
        bool modeWithInterest; // true if mode = with interest, false = without interest
        uint256 supply; // user supply amount
        // the withdrawal limit (e.g. if 10% is the limit, and 100M is supplied, it would be 90M)
        uint256 withdrawalLimit;
        uint256 lastUpdateTimestamp;
        uint256 expandPercent; // withdrawal limit expand percent in 1e2
        uint256 expandDuration; // withdrawal limit expand duration in seconds
        uint256 baseWithdrawalLimit;
        // the current actual max withdrawable amount (e.g. if 10% is the limit, and 100M is supplied, it would be 10M)
        uint256 withdrawableUntilLimit;
        uint256 withdrawable; // actual currently withdrawable amount (supply - withdrawal Limit) & considering balance
    }

    // amounts are always in normal (for withInterest already multiplied with exchange price)
    struct UserBorrowData {
        bool modeWithInterest; // true if mode = with interest, false = without interest
        uint256 borrow; // user borrow amount
        uint256 borrowLimit;
        uint256 lastUpdateTimestamp;
        uint256 expandPercent;
        uint256 expandDuration;
        uint256 baseBorrowLimit;
        uint256 maxBorrowLimit;
        uint256 borrowableUntilLimit; // borrowable amount until any borrow limit (incl. max utilization limit)
        uint256 borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance, max utilization
        uint256 borrowLimitUtilization; // borrow limit for `maxUtilization`
    }
}

File 5 of 10 : iVaultResolver.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

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

interface IFluidVaultResolver {
    function vaultByNftId(uint nftId_) external view returns (address vault_);

    function positionByNftId(
        uint nftId_
    ) external view returns (Structs.UserPosition memory userPosition_, Structs.VaultEntireData memory vaultData_);

    function getVaultVariablesRaw(address vault_) external view returns (uint);

    function getVaultVariables2Raw(address vault_) external view returns (uint);

    function getTickHasDebtRaw(address vault_, int key_) external view returns (uint);

    function getTickDataRaw(address vault_, int tick_) external view returns (uint);

    function getBranchDataRaw(address vault_, uint branch_) external view returns (uint);

    function getPositionDataRaw(address vault_, uint positionId_) external view returns (uint);

    function getAllVaultsAddresses() external view returns (address[] memory vaults_);

    function getVaultLiquidation(
        address vault_,
        uint tokenInAmt_
    ) external returns (Structs.LiquidationStruct memory liquidationData_);

    function getVaultEntireData(address vault_) external view returns (Structs.VaultEntireData memory vaultData_);
}

File 6 of 10 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { IFluidVault } from "../../../protocols/vault/interfaces/iVault.sol";
import { Structs as FluidLiquidityResolverStructs } from "../liquidity/structs.sol";

// @dev Amounts are always in token amount for normal col / normal debt or in
// shares for Dex smart col / smart debt.
contract Structs {
    struct Configs {
        // can be supplyRate instead if Vault Type is smart col. in that case if 1st bit == 1 then positive else negative
        uint16 supplyRateMagnifier;
        // can be borrowRate instead if Vault Type is smart debt. in that case if 1st bit == 1 then positive else negative
        uint16 borrowRateMagnifier;
        uint16 collateralFactor;
        uint16 liquidationThreshold;
        uint16 liquidationMaxLimit;
        uint16 withdrawalGap;
        uint16 liquidationPenalty;
        uint16 borrowFee;
        address oracle;
        // Oracle price is always debt per col, i.e. amount of debt for 1 col.
        // In case of Dex this price can be used to resolve shares values w.r.t. token0 or token1:
        // - T2: debt token per 1 col share
        // - T3: debt shares per 1 col token
        // - T4: debt shares per 1 col share
        uint oraclePriceOperate;
        uint oraclePriceLiquidate;
        address rebalancer;
        uint lastUpdateTimestamp;
    }

    struct ExchangePricesAndRates {
        uint lastStoredLiquiditySupplyExchangePrice; // 0 in case of smart col
        uint lastStoredLiquidityBorrowExchangePrice; // 0 in case of smart debt
        uint lastStoredVaultSupplyExchangePrice;
        uint lastStoredVaultBorrowExchangePrice;
        uint liquiditySupplyExchangePrice; // set to 1e12 in case of smart col
        uint liquidityBorrowExchangePrice; // set to 1e12 in case of smart debt
        uint vaultSupplyExchangePrice;
        uint vaultBorrowExchangePrice;
        uint supplyRateLiquidity; // set to 0 in case of smart col. Must get per token through DexEntireData
        uint borrowRateLiquidity; // set to 0 in case of smart debt. Must get per token through DexEntireData
        // supplyRateVault or borrowRateVault:
        // - when normal col / debt: rate at liquidity + diff rewards or fee through magnifier (rewardsOrFeeRate below)
        // - when smart col / debt: rewards or fee rate at the vault itself. always == rewardsOrFeeRate below.
        // to get the full rates for vault when smart col / debt, combine with data from DexResolver:
        // - rateAtLiquidity for token0 or token1 (DexResolver)
        // - the rewards or fee rate at the vault (VaultResolver)
        // - the Dex APR (currently off-chain compiled through tracking swap events at the DEX)
        int supplyRateVault; // can be negative in case of smart col (meaning pay to supply)
        int borrowRateVault; // can be negative in case of smart debt (meaning get paid to borrow)
        // rewardsOrFeeRateSupply: rewards or fee rate in percent 1e2 precision (1% = 100, 100% = 10000).
        // positive rewards, negative fee.
        // for smart col vaults: supplyRateVault == supplyRateLiquidity.
        // for normal col vaults: relative percent to supplyRateLiquidity, e.g.:
        // when rewards: supplyRateLiquidity = 4%, rewardsOrFeeRateSupply = 20%, supplyRateVault = 4.8%.
        // when fee: supplyRateLiquidity = 4%, rewardsOrFeeRateSupply = -30%, supplyRateVault = 2.8%.
        int rewardsOrFeeRateSupply;
        // rewardsOrFeeRateBorrow: rewards or fee rate in percent 1e2 precision (1% = 100, 100% = 10000).
        // negative rewards, positive fee.
        // for smart debt vaults: borrowRateVault == borrowRateLiquidity.
        // for normal debt vaults: relative percent to borrowRateLiquidity, e.g.:
        // when rewards: borrowRateLiquidity = 4%, rewardsOrFeeRateBorrow = -20%, borrowRateVault = 3.2%.
        // when fee: borrowRateLiquidity = 4%, rewardsOrFeeRateBorrow = 30%, borrowRateVault = 5.2%.
        int rewardsOrFeeRateBorrow;
    }

    struct TotalSupplyAndBorrow {
        uint totalSupplyVault;
        uint totalBorrowVault;
        uint totalSupplyLiquidityOrDex;
        uint totalBorrowLiquidityOrDex;
        uint absorbedSupply;
        uint absorbedBorrow;
    }

    struct LimitsAndAvailability {
        // in case of DEX: withdrawable / borrowable amount of vault at DEX, BUT there could be that DEX can not withdraw
        // that much at Liquidity! So for DEX this must be combined with returned data in DexResolver.
        uint withdrawLimit;
        uint withdrawableUntilLimit;
        uint withdrawable;
        uint borrowLimit;
        uint borrowableUntilLimit; // borrowable amount until any borrow limit (incl. max utilization limit)
        uint borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance, max utilization
        uint borrowLimitUtilization; // borrow limit for `maxUtilization` config at Liquidity
        uint minimumBorrowing;
    }

    struct CurrentBranchState {
        uint status; // if 0 then not liquidated, if 1 then liquidated, if 2 then merged, if 3 then closed
        int minimaTick;
        uint debtFactor;
        uint partials;
        uint debtLiquidity;
        uint baseBranchId;
        int baseBranchMinima;
    }

    struct VaultState {
        uint totalPositions;
        int topTick;
        uint currentBranch;
        uint totalBranch;
        uint totalBorrow;
        uint totalSupply;
        CurrentBranchState currentBranchState;
    }

    struct VaultEntireData {
        address vault;
        bool isSmartCol; // true if col token is a Fluid Dex
        bool isSmartDebt; // true if debt token is a Fluid Dex
        IFluidVault.ConstantViews constantVariables;
        Configs configs;
        ExchangePricesAndRates exchangePricesAndRates;
        TotalSupplyAndBorrow totalSupplyAndBorrow;
        LimitsAndAvailability limitsAndAvailability;
        VaultState vaultState;
        // liquidity related data such as supply amount, limits, expansion etc.
        // Also set for Dex, limits are in shares and same things apply as noted for LimitsAndAvailability above!
        FluidLiquidityResolverStructs.UserSupplyData liquidityUserSupplyData;
        // liquidity related data such as borrow amount, limits, expansion etc.
        // Also set for Dex, limits are in shares and same things apply as noted for LimitsAndAvailability above!
        FluidLiquidityResolverStructs.UserBorrowData liquidityUserBorrowData;
    }

    struct UserPosition {
        uint nftId;
        address owner;
        bool isLiquidated;
        bool isSupplyPosition; // if true that means borrowing is 0
        int tick;
        uint tickId;
        uint beforeSupply;
        uint beforeBorrow;
        uint beforeDustBorrow;
        uint supply;
        uint borrow;
        uint dustBorrow;
    }

    /// @dev liquidation related data
    /// @param vault address of vault
    /// @param token0In address of token in
    /// @param token0Out address of token out
    /// @param token1In address of token in (if smart debt)
    /// @param token1Out address of token out (if smart col)
    /// @param inAmt (without absorb liquidity) minimum of available liquidation
    /// @param outAmt (without absorb liquidity) expected token out, collateral to withdraw
    /// @param inAmtWithAbsorb (absorb liquidity included) minimum of available liquidation. In most cases it'll be same as inAmt but sometimes can be bigger.
    /// @param outAmtWithAbsorb (absorb liquidity included) expected token out, collateral to withdraw. In most cases it'll be same as outAmt but sometimes can be bigger.
    /// @param absorbAvailable true if absorb is available
    /// @dev Liquidity in with absirb will always be >= without asborb. Sometimes without asborb can provide better swaps,
    ///      sometimes with absirb can provide better swaps. But available in with absirb will always be >= One
    struct LiquidationStruct {
        address vault;
        address token0In;
        address token0Out;
        address token1In;
        address token1Out;
        // amounts in case of smart debt are in shares, otherwise token amounts.
        // smart col can not be liquidated so to exchange inAmt always use DexResolver DexState.tokenPerDebtShare
        // and tokenPerColShare for outAmt when Vault is smart col.
        uint inAmt;
        uint outAmt;
        uint inAmtWithAbsorb;
        uint outAmtWithAbsorb;
        bool absorbAvailable;
    }

    struct AbsorbStruct {
        address vault;
        bool absorbAvailable;
    }
}

File 7 of 10 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

contract Structs {
    struct SwapPath {
        ///
        /// @param protocol vault address at which the token pair is available
        address protocol;
        ///
        /// @param tokenIn input token, borrow token at the vault
        address tokenIn;
        ///
        /// @param tokenOut output token, collateral token at the vault
        address tokenOut;
    }

    struct SwapData {
        ///
        /// @param inAmt total input token amount
        uint256 inAmt;
        ///
        /// @param outAmt total output token amount received
        uint256 outAmt;
        ///
        /// @param withAbsorb flag for using mode "withAbsorb" when calling liquidate() on the Vault.
        ///                   Is set to true if a) liquidity without absorb would not
        ///                   cover the desired `inAmt_` or if b) the rate of with absorb is better than without absorb.
        bool withAbsorb;
        ///
        /// @param ratio ratio of outAmt / inAmt scaled by 1e27
        uint256 ratio;
    }

    struct Swap {
        ///
        /// @param path swap path struct info such as protocol where the swap is available
        SwapPath path;
        ///
        /// @param data swap data struct info such as amounts
        SwapData data;
    }
}

File 8 of 10 : variables.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { IFluidVaultResolver } from "../vault/iVaultResolver.sol";

contract Variables {
    IFluidVaultResolver public immutable VAULT_RESOLVER;

    constructor(IFluidVaultResolver vaultResolver_) {
        VAULT_RESOLVER = vaultResolver_;
    }
}

File 9 of 10 : iVault.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

/// @notice common Fluid vaults interface, some methods only available for vaults > T1 (type, simulateLiquidate, rebalance is different)
interface IFluidVault {
    /// @notice returns the vault id
    function VAULT_ID() external view returns (uint256);

    /// @notice returns the vault id
    function TYPE() external view returns (uint256);

    /// @notice reads uint256 data `result_` from storage at a bytes32 storage `slot_` key.
    function readFromStorage(bytes32 slot_) external view returns (uint256 result_);

    struct Tokens {
        address token0;
        address token1;
    }

    struct ConstantViews {
        address liquidity;
        address factory;
        address operateImplementation;
        address adminImplementation;
        address secondaryImplementation;
        address deployer; // address which deploys oracle
        address supply; // either liquidity layer or DEX protocol
        address borrow; // either liquidity layer or DEX protocol
        Tokens supplyToken; // if smart collateral then address of token0 & token1 else just supply token address at token0 and token1 as empty
        Tokens borrowToken; // if smart debt then address of token0 & token1 else just borrow token address at token0 and token1 as empty
        uint256 vaultId;
        uint256 vaultType;
        bytes32 supplyExchangePriceSlot; // if smart collateral then slot is from DEX protocol else from liquidity layer
        bytes32 borrowExchangePriceSlot; // if smart debt then slot is from DEX protocol else from liquidity layer
        bytes32 userSupplySlot; // if smart collateral then slot is from DEX protocol else from liquidity layer
        bytes32 userBorrowSlot; // if smart debt then slot is from DEX protocol else from liquidity layer
    }

    /// @notice returns all Vault constants
    function constantsView() external view returns (ConstantViews memory constantsView_);

    /// @notice fetches the latest user position after a liquidation
    function fetchLatestPosition(
        int256 positionTick_,
        uint256 positionTickId_,
        uint256 positionRawDebt_,
        uint256 tickData_
    )
        external
        view
        returns (
            int256, // tick
            uint256, // raw debt
            uint256, // raw collateral
            uint256, // branchID_
            uint256 // branchData_
        );

    /// @notice calculates the updated vault exchange prices
    function updateExchangePrices(
        uint256 vaultVariables2_
    )
        external
        view
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice calculates the updated vault exchange prices and writes them to storage
    function updateExchangePricesOnStorage()
        external
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice returns the liquidity contract address
    function LIQUIDITY() external view returns (address);

    error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);

    function rebalance(
        int colToken0MinMax_,
        int colToken1MinMax_,
        int debtToken0MinMax_,
        int debtToken1MinMax_
    ) external payable returns (int supplyAmt_, int borrowAmt_);

    /// @notice reverts with FluidLiquidateResult
    function simulateLiquidate(uint debtAmt_, bool absorb_) external;
}

File 10 of 10 : iVaultT1.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

interface IFluidVaultT1 {
    /// @notice returns the vault id
    function VAULT_ID() external view returns (uint256);

    /// @notice reads uint256 data `result_` from storage at a bytes32 storage `slot_` key.
    function readFromStorage(bytes32 slot_) external view returns (uint256 result_);

    struct ConstantViews {
        address liquidity;
        address factory;
        address adminImplementation;
        address secondaryImplementation;
        address supplyToken;
        address borrowToken;
        uint8 supplyDecimals;
        uint8 borrowDecimals;
        uint vaultId;
        bytes32 liquiditySupplyExchangePriceSlot;
        bytes32 liquidityBorrowExchangePriceSlot;
        bytes32 liquidityUserSupplySlot;
        bytes32 liquidityUserBorrowSlot;
    }

    /// @notice returns all Vault constants
    function constantsView() external view returns (ConstantViews memory constantsView_);

    /// @notice fetches the latest user position after a liquidation
    function fetchLatestPosition(
        int256 positionTick_,
        uint256 positionTickId_,
        uint256 positionRawDebt_,
        uint256 tickData_
    )
        external
        view
        returns (
            int256, // tick
            uint256, // raw debt
            uint256, // raw collateral
            uint256, // branchID_
            uint256 // branchData_
        );

    /// @notice calculates the updated vault exchange prices
    function updateExchangePrices(
        uint256 vaultVariables2_
    )
        external
        view
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice calculates the updated vault exchange prices and writes them to storage
    function updateExchangePricesOnStorage()
        external
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice returns the liquidity contract address
    function LIQUIDITY() external view returns (address);

    function operate(
        uint256 nftId_, // if 0 then new position
        int256 newCol_, // if negative then withdraw
        int256 newDebt_, // if negative then payback
        address to_ // address at which the borrow & withdraw amount should go to. If address(0) then it'll go to msg.sender
    )
        external
        payable
        returns (
            uint256, // nftId_
            int256, // final supply amount. if - then withdraw
            int256 // final borrow amount. if - then payback
        );

    function liquidate(
        uint256 debtAmt_,
        uint256 colPerUnitDebt_, // min collateral needed per unit of debt in 1e18
        address to_,
        bool absorb_
    ) external payable returns (uint actualDebtAmt_, uint actualColAmt_);

    function absorb() external;

    function rebalance() external payable returns (int supplyAmt_, int borrowAmt_);

    error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IFluidVaultResolver","name":"vaultResolver_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FluidVaultLiquidationsResolver__AddressZero","type":"error"},{"inputs":[],"name":"FluidVaultLiquidationsResolver__InvalidParams","type":"error"},{"inputs":[],"name":"VAULT_RESOLVER","outputs":[{"internalType":"contract IFluidVaultResolver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"},{"internalType":"uint256","name":"outAmt_","type":"uint256"}],"name":"approxOutput","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"},{"internalType":"uint256","name":"inAmt_","type":"uint256"},{"internalType":"uint256","name":"approxOutAmt_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"},{"internalType":"uint256","name":"inAmt_","type":"uint256"}],"name":"exactInput","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"},{"internalType":"uint256","name":"actualInAmt_","type":"uint256"},{"internalType":"uint256","name":"outAmt_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"},{"internalType":"uint256","name":"targetApproxOutAmt_","type":"uint256"}],"name":"filterToApproxOutAmt","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"filteredSwaps_","type":"tuple[]"},{"internalType":"uint256","name":"actualInAmt_","type":"uint256"},{"internalType":"uint256","name":"approxOutAmt_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"},{"internalType":"uint256","name":"targetInAmt_","type":"uint256"}],"name":"filterToTargetInAmt","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"filteredSwaps_","type":"tuple[]"},{"internalType":"uint256","name":"actualInAmt_","type":"uint256"},{"internalType":"uint256","name":"approxOutAmt_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllSwapPaths","outputs":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath[]","name":"paths_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllVaultsSwap","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllVaultsSwapData","outputs":[{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData[]","name":"withoutAbsorb_","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData[]","name":"withAbsorb_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllVaultsSwapRaw","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokensIn_","type":"address[]"},{"internalType":"address[]","name":"tokensOut_","type":"address[]"}],"name":"getAnySwapPaths","outputs":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath[]","name":"paths_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokensIn_","type":"address[]"},{"internalType":"address[]","name":"tokensOut_","type":"address[]"}],"name":"getAnySwaps","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokensIn_","type":"address[]"},{"internalType":"address[]","name":"tokensOut_","type":"address[]"}],"name":"getAnySwapsRaw","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"protocol_","type":"address"}],"name":"getSwapForProtocol","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap","name":"swap_","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"}],"name":"getSwapPaths","outputs":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath[]","name":"paths_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap","name":"swap_","type":"tuple"},{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"slippage_","type":"uint256"}],"name":"getSwapTx","outputs":[{"internalType":"address","name":"target_","type":"address"},{"internalType":"bytes","name":"calldata_","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"},{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"slippage_","type":"uint256"}],"name":"getSwapTxs","outputs":[{"internalType":"address[]","name":"targets_","type":"address[]"},{"internalType":"bytes[]","name":"calldatas_","type":"bytes[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"}],"name":"getSwaps","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath[]","name":"paths_","type":"tuple[]"}],"name":"getSwapsForPaths","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath[]","name":"paths_","type":"tuple[]"}],"name":"getSwapsForPathsRaw","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"}],"name":"getSwapsRaw","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getVaultSwapData","outputs":[{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"withoutAbsorb_","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"withAbsorb_","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"vaults_","type":"address[]"}],"name":"getVaultsSwap","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"vaults_","type":"address[]"}],"name":"getVaultsSwapData","outputs":[{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData[]","name":"withoutAbsorb_","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData[]","name":"withAbsorb_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"vaults_","type":"address[]"}],"name":"getVaultsSwapRaw","outputs":[{"components":[{"components":[{"internalType":"address","name":"protocol","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"}],"internalType":"struct Structs.SwapPath","name":"path","type":"tuple"},{"components":[{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"bool","name":"withAbsorb","type":"bool"},{"internalType":"uint256","name":"ratio","type":"uint256"}],"internalType":"struct Structs.SwapData","name":"data","type":"tuple"}],"internalType":"struct Structs.Swap[]","name":"swaps_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b5060405162003ba538038062003ba5833981016040819052620000349162000068565b6001600160a01b038116608081905262000061576040516303c99f9d60e61b815260040160405180910390fd5b506200009a565b6000602082840312156200007b57600080fd5b81516001600160a01b03811681146200009357600080fd5b9392505050565b608051613ad3620000d2600039600081816102b3015281816113ea01528181611c3001528181611e49015261209e0152613ad36000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c80637f3e2b48116100e35780639f5de8751161008c578063e082bca211610066578063e082bca2146103bb578063e979e874146103ce578063ed6bf8bc146103d657600080fd5b80639f5de87514610375578063aa822df614610395578063c5f8b2e5146103a857600080fd5b8063861d3ac4116100bd578063861d3ac4146103205780638651d5ec146103415780638953b9d61461035457600080fd5b80637f3e2b48146102ae5780638011ba33146102fa578063838fef5c1461030d57600080fd5b80635a980a9f116101455780636c8559621161011f5780636c855962146102755780637119484a146102885780637bfb86ff1461029b57600080fd5b80635a980a9f1461023c5780635e47ec031461024f57806365eb6bd41461026257600080fd5b8063404fcab211610176578063404fcab2146101f15780634296bdff146102135780634c6fdc1a1461022957600080fd5b806321d3b7f41461019d578063232306ea146101bb5780633c199241146101dc575b600080fd5b6101a56103e9565b6040516101b29190612d80565b60405180910390f35b6101ce6101c9366004612db8565b6103fb565b6040516101b2929190612ea8565b6101e4610541565b6040516101b29190612f74565b6102046101ff366004612ff1565b6106b9565b6040516101b293929190613032565b61021b6106e1565b6040516101b29291906130b4565b61021b61023736600461320f565b6106f7565b6101e461024a3660046132ef565b61086f565b61020461025d3660046133df565b610b96565b610204610270366004612ff1565b610bd3565b6101a56102833660046132ef565b610beb565b6101a561029636600461320f565b610c05565b6101a56102a936600461320f565b610ea7565b6102d57f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b2565b6101a561030836600461350a565b6110b1565b6101a561031b36600461350a565b6110c9565b61033361032e366004613543565b6110d8565b6040516101b292919061358c565b61020461034f3660046133df565b611311565b6103676103623660046135c3565b611341565b6040516101b29291906135e7565b6103886103833660046135c3565b6114e2565b6040516101b29190613637565b6101e46103a336600461350a565b61157f565b6101a56103b63660046132ef565b611805565b6101a56103c9366004613645565b611816565b6101a5611ab9565b6101a56103e4366004613645565b611ac6565b60606103f66102a9611c29565b905090565b6060808467ffffffffffffffff811115610417576104176130d9565b604051908082528060200260200182016040528015610440578160200160208202803683370190505b5091508467ffffffffffffffff81111561045c5761045c6130d9565b60405190808252806020026020018201604052801561048f57816020015b606081526020019060019003908161047a5790505b50905060005b85811015610537576104bf8787838181106104b2576104b26136df565b905060e0020186866110d8565b8483815181106104d1576104d16136df565b602002602001018484815181106104ea576104ea6136df565b602002602001018290528273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505050806105309061373d565b9050610495565b5094509492505050565b6060600061054d611c29565b9050805167ffffffffffffffff811115610569576105696130d9565b6040519080825280602002602001820160405280156105d257816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816105875790505b50915060008060005b83518110156106b2576106068482815181106105f9576105f96136df565b6020026020010151611ce7565b8093508194505050604051806060016040528085838151811061062b5761062b6136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff16815250858281518110610696576106966136df565b6020026020010181905250806106ab9061373d565b90506105db565b5050505090565b60606000806106d16106cb87876110c9565b85610b96565b9250925092505b93509350939050565b6060806106ef610237611c29565b915091509091565b606080825167ffffffffffffffff811115610714576107146130d9565b60405190808252806020026020018201604052801561077257816020015b61075f60405180608001604052806000815260200160008152602001600015158152602001600081525090565b8152602001906001900390816107325790505b509150825167ffffffffffffffff81111561078f5761078f6130d9565b6040519080825280602002602001820160405280156107ed57816020015b6107da60405180608001604052806000815260200160008152602001600015158152602001600081525090565b8152602001906001900390816107ad5790505b50905060005b83518110156108695761081e848281518110610811576108116136df565b6020026020010151611341565b848381518110610830576108306136df565b60200260200101848481518110610849576108496136df565b602002602001018290528290525050806108629061373d565b90506107f3565b50915091565b6060600061087d8386613775565b67ffffffffffffffff811115610895576108956130d9565b6040519080825280602002602001820160405280156108fe57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816108b35790505b509050600061090b611c29565b90506000806000805b8451811015610ab8576109328582815181106105f9576105f96136df565b909350915060005b8a811015610aaf5760005b89811015610aa6578c8c8381811061095f5761095f6136df565b905060200201602081019061097491906135c3565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156109ff57508a8a828181106109bb576109bb6136df565b90506020020160208101906109d091906135c3565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b15610a9e576040518060600160405280888581518110610a2157610a216136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff16815250888781518110610a8c57610a8c6136df565b60200260200101819052508560010195505b600101610945565b5060010161093a565b50600101610914565b508267ffffffffffffffff811115610ad257610ad26130d9565b604051908082528060200260200182016040528015610b3b57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610af05790505b50955060005b83811015610b8857858181518110610b5b57610b5b6136df565b6020026020010151878281518110610b7557610b756136df565b6020908102919091010152600101610b41565b505050505050949350505050565b6060600080610bc685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611d72565b9250925092509250925092565b60606000806106d1610be587876110c9565b85611311565b6060610bfc6103c98686868661086f565b95945050505050565b6060600080835160020267ffffffffffffffff811115610c2757610c276130d9565b604051908082528060200260200182016040528015610c6057816020015b610c4d612c6c565b815260200190600190039081610c455790505b509050610c9060405180608001604052806000815260200160008152602001600015158152602001600081525090565b610cbd60405180608001604052806000815260200160008152602001600015158152602001600081525090565b60008060005b8851811015610e9057610ce1898281518110610811576108116136df565b8051919650945015610e88578451845160019098019703610d055760008452610d13565b845115610d13578660010196505b610d288982815181106105f9576105f96136df565b8093508194505050604051806040016040528060405180606001604052808c8581518110610d5857610d586136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff16815250815260200186815250868260020281518110610dcf57610dcf6136df565b6020026020010181905250604051806040016040528060405180606001604052808c8581518110610e0257610e026136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff16815250815260200185815250868260020260010181518110610e7c57610e7c6136df565b60200260200101819052505b600101610cc3565b50610e9b85876123a3565b98975050505050505050565b6060600080835167ffffffffffffffff811115610ec657610ec66130d9565b604051908082528060200260200182016040528015610eff57816020015b610eec612c6c565b815260200190600190039081610ee45790505b509050610f2f60405180608001604052806000815260200160008152602001600015158152602001600081525090565b610f5c60405180608001604052806000815260200160008152602001600015158152602001600081525090565b610f64612c6c565b60005b875181101561109b57610f85888281518110610811576108116136df565b8094508195505050604051806040016040528060405180606001604052808b8581518110610fb557610fb56136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815250815260200161101f868661247f565b9052602081015151909250156110935785600101955061104a8882815181106105f9576105f96136df565b835173ffffffffffffffffffffffffffffffffffffffff9182166040820152911660209091015284518290869083908110611087576110876136df565b60200260200101819052505b600101610f67565b506110a684866123a3565b979650505050505050565b60606110c06103e4848461157f565b90505b92915050565b60606110c06103c9848461157f565b60006060816110ea60208701876135c3565b73ffffffffffffffffffffffffffffffffffffffff161480611120575073ffffffffffffffffffffffffffffffffffffffff8416155b15611157576040517ff267e74000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620f42408310158061116b57506060850135155b8061117857506080850135155b156111af576040517fb55de08000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608601356111cc6080880135670de0b6b3a7640000613775565b6111d6919061378c565b9050620f42406111e685826137c7565b6111f09083613775565b6111fa919061378c565b905061120960208701876135c3565b507f8433ea22000000000000000000000000000000000000000000000000000000006060870135828761124260c08b0160a08c016137da565b6040516024810194909452604484019290925273ffffffffffffffffffffffffffffffffffffffff1660648301521515608482015260a401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529250611306908701876135c3565b925050935093915050565b6060600080610bc6857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86611d72565b61136e60405180608001604052806000815260200160008152602001600015158152602001600081525090565b61139b60405180608001604052806000815260200160008152602001600015158152602001600081525090565b6040517f1fcd364900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152600060248301819052917f000000000000000000000000000000000000000000000000000000000000000090911690631fcd364990604401610140604051808303816000875af1158015611436573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145a9190613812565b905060405180608001604052808260a0015181526020018260c0015181526020016000151581526020016114968360a001518460c00151612500565b815250925060405180608001604052808260e00151815260200182610100015181526020016001151581526020016114d78360e00151846101000151612500565b815250915050915091565b6114ea612c6c565b73ffffffffffffffffffffffffffffffffffffffff821661150a57919050565b60008061151684611ce7565b9150915060008061152686611341565b6040805160a08101825273ffffffffffffffffffffffffffffffffffffffff808b16928201928352888116606083015287166080820152908152919350915060208101611573848461247f565b90529695505050505050565b6060600061158b611c29565b9050600080825167ffffffffffffffff8111156115aa576115aa6130d9565b6040519080825280602002602001820160405280156115d3578160200160208202803683370190505b50905060008060005b85518110156116c4576115fa8682815181106105f9576105f96136df565b909350915073ffffffffffffffffffffffffffffffffffffffff808416908a1614801561165257508773ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b156116b457858181518110611669576116696136df565b6020026020010151848681518110611683576116836136df565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526116b18561373d565b94505b6116bd8161373d565b90506115dc565b508367ffffffffffffffff8111156116de576116de6130d9565b60405190808252806020026020018201604052801561174757816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816116fc5790505b50955060005b848110156117f9576040518060600160405280858381518110611772576117726136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff168152508782815181106117dd576117dd6136df565b6020026020010181905250806117f29061373d565b905061174d565b50505050505092915050565b6060610bfc6103e48686868661086f565b60606000825160020267ffffffffffffffff811115611837576118376130d9565b60405190808252806020026020018201604052801561187057816020015b61185d612c6c565b8152602001906001900390816118555790505b50905060006118a260405180608001604052806000815260200160008152602001600015158152602001600081525090565b6118cf60405180608001604052806000815260200160008152602001600015158152602001600081525090565b60005b86518110156119db576119018782815181106118f0576118f06136df565b602002602001015160000151611341565b80519194509250156119d35782518251600190950194036119255760008252611933565b825115611933578360010193505b6040518060400160405280888381518110611950576119506136df565b6020026020010151815260200184815250858260020281518110611976576119766136df565b6020026020010181905250604051806040016040528088838151811061199e5761199e6136df565b60200260200101518152602001838152508582600202600101815181106119c7576119c76136df565b60200260200101819052505b6001016118d2565b508267ffffffffffffffff8111156119f5576119f56130d9565b604051908082528060200260200182016040528015611a2e57816020015b611a1b612c6c565b815260200190600190039081611a135790505b5094506000805b8551811015611aae576000868281518110611a5257611a526136df565b602002602001015160200151600001511115611aa657858181518110611a7a57611a7a6136df565b6020026020010151878381518110611a9457611a946136df565b60200260200101819052508160010191505b600101611a35565b505050505050919050565b60606103f6610296611c29565b60606000825167ffffffffffffffff811115611ae457611ae46130d9565b604051908082528060200260200182016040528015611b1d57816020015b611b0a612c6c565b815260200190600190039081611b025790505b5090506000611b2a612c6c565b611b5760405180608001604052806000815260200160008152602001600015158152602001600081525090565b611b8460405180608001604052806000815260200160008152602001600015158152602001600081525090565b60005b8751811015611c1e57611ba58882815181106118f0576118f06136df565b80935081945050506040518060400160405280898381518110611bca57611bca6136df565b60200260200101518152602001611be1858561247f565b905260208101515190945015611c165784600101945083868281518110611c0a57611c0a6136df565b60200260200101819052505b600101611b87565b506110a685856123a3565b60606103f67f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a8d9f4936040518163ffffffff1660e01b8152600401600060405180830381865afa158015611c99573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cdf91908101906138bf565b612710612533565b60008060008373ffffffffffffffffffffffffffffffffffffffff1663b7791bf26040518163ffffffff1660e01b81526004016101a060405180830381865afa158015611d38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5c919061395f565b90508060a0015181608001519250925050915091565b6060600080611d8086612768565b9550611d8d8686866128b9565b9194509250905084821180611da157508381115b156106d857600060018451611db691906137c7565b9050600086841115611e0b57611dcc87856137c7565b858381518110611dde57611dde6136df565b602002602001015160200151600001516001611dfa9190613a3c565b611e0491906137c7565b905061209a565b6000611e1787856137c7565b868481518110611e2957611e296136df565b60200260200101516020015160200151611e4391906137c7565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631fcd3649888681518110611e9557611e956136df565b602090810291909101015151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260006024820152604401610140604051808303816000875af1158015611f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f399190613812565b90506000611f4f8260a001518360c00151612500565b90506000611f848360a001518460e00151611f6a91906137c7565b8460c00151856101000151611f7f91906137c7565b612500565b905081811180611f975750838360c00151105b156120665760008360c00151846101000151611fb391906137c7565b9050848110611fef5781611fd3866b033b2e3c9fd0803ce8000000613775565b611fdd919061378c565b611fe8906001613a3c565b9550612060565b81612006826b033b2e3c9fd0803ce8000000613775565b612010919061378c565b61201b906001613a3c565b95508261202882876137c7565b61203e906b033b2e3c9fd0803ce8000000613775565b612048919061378c565b612053906001613a3c565b61205d9087613a3c565b95505b50612095565b8161207d856b033b2e3c9fd0803ce8000000613775565b612087919061378c565b612092906001613a3c565b94505b505050505b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631fcd36498785815181106120ea576120ea6136df565b602090810291909101015151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101859052604401610140604051808303816000875af115801561216a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218e9190613812565b90508583815181106121a2576121a26136df565b60200260200101516020015160000151856121bd91906137c7565b94508583815181106121d1576121d16136df565b60200260200101516020015160200151846121ec91906137c7565b9350858381518110612200576122006136df565b60200260200101516020015160400151156122aa578060e0015186848151811061222c5761222c6136df565b6020026020010151602001516000018181525050806101000151868481518110612258576122586136df565b602002602001015160200151602001818152505061227f8160e00151826101000151612500565b868481518110612291576122916136df565b6020026020010151602001516060018181525050612339565b8060a001518684815181106122c1576122c16136df565b60200260200101516020015160000181815250508060c001518684815181106122ec576122ec6136df565b60200260200101516020015160200181815250506123128160a001518260c00151612500565b868481518110612324576123246136df565b60200260200101516020015160600181815250505b85838151811061234b5761234b6136df565b60200260200101516020015160000151856123669190613a3c565b945085838151811061237a5761237a6136df565b60200260200101516020015160200151846123959190613a3c565b935050505093509350939050565b60608167ffffffffffffffff8111156123be576123be6130d9565b6040519080825280602002602001820160405280156123f757816020015b6123e4612c6c565b8152602001906001900390816123dc5790505b5090506000805b845181101561247757600085828151811061241b5761241b6136df565b60200260200101516020015160000151111561246f57848181518110612443576124436136df565b602002602001015183838151811061245d5761245d6136df565b60200260200101819052508160010191505b6001016123fe565b505092915050565b6124ac60405180608001604052806000815260200160008152602001600015158152602001600081525090565b81516000036124bc5750806110c3565b8260600151826060015111156124d35750806110c3565b82606001518260600151036124f95782518251036124f25750816110c3565b50806110c3565b5090919050565b600081600003612512575060006110c3565b82612529836b033b2e3c9fd0803ce8000000613775565b6110c0919061378c565b8151606090600090815b855181101561264957858181518110612558576125586136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1663bb24fe8a6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156125e4575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526125e191810190613a4f565b60015b6125f25761271092506125f5565b92505b848314612641576000868281518110612610576126106136df565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261263e82613a68565b91505b60010161253d565b508067ffffffffffffffff811115612663576126636130d9565b60405190808252806020026020018201604052801561268c578160200160208202803683370190505b5092506000805b865181101561275e57600073ffffffffffffffffffffffffffffffffffffffff168782815181106126c6576126c66136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614612756578681815181106126fb576126fb6136df565b6020026020010151858381518110612715576127156136df565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508160010191505b600101612693565b5050505092915050565b60606000612774612c6c565b60015b84518110156128b0576000925060005b81865161279491906137c7565b81101561288f578581815181106127ad576127ad6136df565b60200260200101516020015160600151868260016127cb9190613a3c565b815181106127db576127db6136df565b60200260200101516020015160600151111561287d57858181518110612803576128036136df565b602002602001015192508581600161281b9190613a3c565b8151811061282b5761282b6136df565b6020026020010151868281518110612845576128456136df565b6020908102919091010152828661285d836001613a3c565b8151811061286d5761286d6136df565b6020026020010181905250600193505b806128878161373d565b915050612787565b508261289e5750929392505050565b806128a88161373d565b915050612777565b50929392505050565b606060008085516000036128d5575084915060009050806106d8565b60005b85831080156128e657508482105b80156128f25750865181105b1561296557868181518110612909576129096136df565b60200260200101516020015160000151836129249190613a3c565b9250868181518110612938576129386136df565b60200260200101516020015160200151826129539190613a3c565b915061295e8161373d565b90506128d8565b6000805b6129746001846137c7565b811015612aaa576000612988826001613a3c565b90505b83811015612a99578981815181106129a5576129a56136df565b6020026020010151600001516000015173ffffffffffffffffffffffffffffffffffffffff168a83815181106129dd576129dd6136df565b6020026020010151600001516000015173ffffffffffffffffffffffffffffffffffffffff1603612a8957898281518110612a1a57612a1a6136df565b6020026020010151602001516040015115612a575760008a8281518110612a4357612a436136df565b602090810291909101810151015152612a7b565b60008a8381518110612a6b57612a6b6136df565b6020908102919091018101510151525b82612a858161373d565b9350505b612a928161373d565b905061298b565b50612aa38161373d565b9050612969565b508015612bb8576000818951612ac091906137c7565b67ffffffffffffffff811115612ad857612ad86130d9565b604051908082528060200260200182016040528015612b1157816020015b612afe612c6c565b815260200190600190039081612af65790505b50955060005b8951811015612b9e5760008a8281518110612b3457612b346136df565b602002602001015160200151600001511115612b8e57898181518110612b5c57612b5c6136df565b6020026020010151878381518110612b7657612b766136df565b602002602001018190525081612b8b9061373d565b91505b612b978161373d565b9050612b17565b50612baa8689896128b9565b9550955095505050506106d8565b8167ffffffffffffffff811115612bd157612bd16130d9565b604051908082528060200260200182016040528015612c0a57816020015b612bf7612c6c565b815260200190600190039081612bef5790505b50945060005b82811015612c6057888181518110612c2a57612c2a6136df565b6020026020010151868281518110612c4457612c446136df565b602002602001018190525080612c599061373d565b9050612c10565b50505093509350939050565b6040805160a08101825260009181018281526060820183905260808201929092529081908152602001612cc260405180608001604052806000815260200160008152602001600015158152602001600081525090565b905290565b612d01828251805173ffffffffffffffffffffffffffffffffffffffff908116835260208083015182169084015260409182015116910152565b6020810151612d3660608401828051825260208101516020830152604081015115156040830152606081015160608301525050565b505050565b600081518084526020808501945080840160005b83811015612d7557612d62878351612cc7565b60e0969096019590820190600101612d4f565b509495945050505050565b6020815260006110c06020830184612d3b565b73ffffffffffffffffffffffffffffffffffffffff81168114612db557600080fd5b50565b60008060008060608587031215612dce57600080fd5b843567ffffffffffffffff80821115612de657600080fd5b818701915087601f830112612dfa57600080fd5b813581811115612e0957600080fd5b88602060e083028501011115612e1e57600080fd5b60209283019650945050850135612e3481612d93565b9396929550929360400135925050565b6000815180845260005b81811015612e6a57602081850181015186830182015201612e4e565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b604080825283519082018190526000906020906060840190828701845b82811015612ef757815173ffffffffffffffffffffffffffffffffffffffff1684529284019290840190600101612ec5565b50505083810382850152845180825282820190600581901b8301840187850160005b83811015612f65577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018552612f53838351612e44565b94870194925090860190600101612f19565b50909998505050505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612fe557612fd2838551805173ffffffffffffffffffffffffffffffffffffffff908116835260208083015182169084015260409182015116910152565b9284019260609290920191600101612f90565b50909695505050505050565b60008060006060848603121561300657600080fd5b833561301181612d93565b9250602084013561302181612d93565b929592945050506040919091013590565b6060815260006130456060830186612d3b565b60208301949094525060400152919050565b600081518084526020808501945080840160005b83811015612d75576130a18783518051825260208101516020830152604081015115156040830152606081015160608301525050565b608096909601959082019060010161306b565b6040815260006130c76040830185613057565b8281036020840152610bfc8185613057565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561312b5761312b6130d9565b60405290565b6040516080810167ffffffffffffffff8111828210171561312b5761312b6130d9565b604051610140810167ffffffffffffffff8111828210171561312b5761312b6130d9565b6040516101a0810167ffffffffffffffff8111828210171561312b5761312b6130d9565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156131e3576131e36130d9565b604052919050565b600067ffffffffffffffff821115613205576132056130d9565b5060051b60200190565b6000602080838503121561322257600080fd5b823567ffffffffffffffff81111561323957600080fd5b8301601f8101851361324a57600080fd5b803561325d613258826131eb565b61319c565b81815260059190911b8201830190838101908783111561327c57600080fd5b928401925b828410156110a657833561329481612d93565b82529284019290840190613281565b60008083601f8401126132b557600080fd5b50813567ffffffffffffffff8111156132cd57600080fd5b6020830191508360208260051b85010111156132e857600080fd5b9250929050565b6000806000806040858703121561330557600080fd5b843567ffffffffffffffff8082111561331d57600080fd5b613329888389016132a3565b9096509450602087013591508082111561334257600080fd5b5061334f878288016132a3565b95989497509550505050565b60006060828403121561336d57600080fd5b6040516060810181811067ffffffffffffffff82111715613390576133906130d9565b60405290508082356133a181612d93565b815260208301356133b181612d93565b602082015260408301356133c481612d93565b6040919091015292915050565b8015158114612db557600080fd5b60008060408084860312156133f357600080fd5b833567ffffffffffffffff81111561340a57600080fd5b8401601f8101861361341b57600080fd5b8035602061342b613258836131eb565b82815260e0928302840182019282820191908a85111561344a57600080fd5b948301945b848610156134f957858b03818112156134685760008081fd5b613470613108565b61347a8d8961335b565b815260606080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0850112156134b05760008081fd5b6134b8613131565b8a8301358152908a013588820152925060a08901356134d6816133d1565b838b015260c089013590830152808601919091528352948501949183019161344f565b509997909101359750505050505050565b6000806040838503121561351d57600080fd5b823561352881612d93565b9150602083013561353881612d93565b809150509250929050565b600080600083850361012081121561355a57600080fd5b60e081121561356857600080fd5b5083925060e084013561357a81612d93565b92959294505050610100919091013590565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006135bb6040830184612e44565b949350505050565b6000602082840312156135d557600080fd5b81356135e081612d93565b9392505050565b825181526020808401518183015260408085015115158184015260608086015181850152845160808501529184015160a0840152830151151560c083015282015160e082015261010081016135e0565b60e081016110c38284612cc7565b6000602080838503121561365857600080fd5b823567ffffffffffffffff81111561366f57600080fd5b8301601f8101851361368057600080fd5b803561368e613258826131eb565b818152606091820283018401918482019190888411156136ad57600080fd5b938501935b838510156136d3576136c4898661335b565b835293840193918501916136b2565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361376e5761376e61370e565b5060010190565b80820281158282048414176110c3576110c361370e565b6000826137c2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156110c3576110c361370e565b6000602082840312156137ec57600080fd5b81356135e0816133d1565b805161380281612d93565b919050565b8051613802816133d1565b6000610140828403121561382557600080fd5b61382d613154565b613836836137f7565b8152613844602084016137f7565b6020820152613855604084016137f7565b6040820152613866606084016137f7565b6060820152613877608084016137f7565b608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206138b4818501613807565b908201529392505050565b600060208083850312156138d257600080fd5b825167ffffffffffffffff8111156138e957600080fd5b8301601f810185136138fa57600080fd5b8051613908613258826131eb565b81815260059190911b8201830190838101908783111561392757600080fd5b928401925b828410156110a657835161393f81612d93565b8252928401929084019061392c565b805160ff8116811461380257600080fd5b60006101a0828403121561397257600080fd5b61397a613178565b613983836137f7565b8152613991602084016137f7565b60208201526139a2604084016137f7565b60408201526139b3606084016137f7565b60608201526139c4608084016137f7565b60808201526139d560a084016137f7565b60a08201526139e660c0840161394e565b60c08201526139f760e0840161394e565b60e08201526101008381015190820152610120808401519082015261014080840151908201526101608084015190820152610180928301519281019290925250919050565b808201808211156110c3576110c361370e565b600060208284031215613a6157600080fd5b5051919050565b600081613a7757613a7761370e565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea26469706673582212204a67e6a867ff566c7338aa7dab6c38751989ef164ccdf002c8b4f95df5935e0064736f6c63430008150033000000000000000000000000d6c90a7b61f3e0ac04e2f4b0359ab0ac09035507

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101985760003560e01c80637f3e2b48116100e35780639f5de8751161008c578063e082bca211610066578063e082bca2146103bb578063e979e874146103ce578063ed6bf8bc146103d657600080fd5b80639f5de87514610375578063aa822df614610395578063c5f8b2e5146103a857600080fd5b8063861d3ac4116100bd578063861d3ac4146103205780638651d5ec146103415780638953b9d61461035457600080fd5b80637f3e2b48146102ae5780638011ba33146102fa578063838fef5c1461030d57600080fd5b80635a980a9f116101455780636c8559621161011f5780636c855962146102755780637119484a146102885780637bfb86ff1461029b57600080fd5b80635a980a9f1461023c5780635e47ec031461024f57806365eb6bd41461026257600080fd5b8063404fcab211610176578063404fcab2146101f15780634296bdff146102135780634c6fdc1a1461022957600080fd5b806321d3b7f41461019d578063232306ea146101bb5780633c199241146101dc575b600080fd5b6101a56103e9565b6040516101b29190612d80565b60405180910390f35b6101ce6101c9366004612db8565b6103fb565b6040516101b2929190612ea8565b6101e4610541565b6040516101b29190612f74565b6102046101ff366004612ff1565b6106b9565b6040516101b293929190613032565b61021b6106e1565b6040516101b29291906130b4565b61021b61023736600461320f565b6106f7565b6101e461024a3660046132ef565b61086f565b61020461025d3660046133df565b610b96565b610204610270366004612ff1565b610bd3565b6101a56102833660046132ef565b610beb565b6101a561029636600461320f565b610c05565b6101a56102a936600461320f565b610ea7565b6102d57f000000000000000000000000d6c90a7b61f3e0ac04e2f4b0359ab0ac0903550781565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b2565b6101a561030836600461350a565b6110b1565b6101a561031b36600461350a565b6110c9565b61033361032e366004613543565b6110d8565b6040516101b292919061358c565b61020461034f3660046133df565b611311565b6103676103623660046135c3565b611341565b6040516101b29291906135e7565b6103886103833660046135c3565b6114e2565b6040516101b29190613637565b6101e46103a336600461350a565b61157f565b6101a56103b63660046132ef565b611805565b6101a56103c9366004613645565b611816565b6101a5611ab9565b6101a56103e4366004613645565b611ac6565b60606103f66102a9611c29565b905090565b6060808467ffffffffffffffff811115610417576104176130d9565b604051908082528060200260200182016040528015610440578160200160208202803683370190505b5091508467ffffffffffffffff81111561045c5761045c6130d9565b60405190808252806020026020018201604052801561048f57816020015b606081526020019060019003908161047a5790505b50905060005b85811015610537576104bf8787838181106104b2576104b26136df565b905060e0020186866110d8565b8483815181106104d1576104d16136df565b602002602001018484815181106104ea576104ea6136df565b602002602001018290528273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505050806105309061373d565b9050610495565b5094509492505050565b6060600061054d611c29565b9050805167ffffffffffffffff811115610569576105696130d9565b6040519080825280602002602001820160405280156105d257816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816105875790505b50915060008060005b83518110156106b2576106068482815181106105f9576105f96136df565b6020026020010151611ce7565b8093508194505050604051806060016040528085838151811061062b5761062b6136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff16815250858281518110610696576106966136df565b6020026020010181905250806106ab9061373d565b90506105db565b5050505090565b60606000806106d16106cb87876110c9565b85610b96565b9250925092505b93509350939050565b6060806106ef610237611c29565b915091509091565b606080825167ffffffffffffffff811115610714576107146130d9565b60405190808252806020026020018201604052801561077257816020015b61075f60405180608001604052806000815260200160008152602001600015158152602001600081525090565b8152602001906001900390816107325790505b509150825167ffffffffffffffff81111561078f5761078f6130d9565b6040519080825280602002602001820160405280156107ed57816020015b6107da60405180608001604052806000815260200160008152602001600015158152602001600081525090565b8152602001906001900390816107ad5790505b50905060005b83518110156108695761081e848281518110610811576108116136df565b6020026020010151611341565b848381518110610830576108306136df565b60200260200101848481518110610849576108496136df565b602002602001018290528290525050806108629061373d565b90506107f3565b50915091565b6060600061087d8386613775565b67ffffffffffffffff811115610895576108956130d9565b6040519080825280602002602001820160405280156108fe57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816108b35790505b509050600061090b611c29565b90506000806000805b8451811015610ab8576109328582815181106105f9576105f96136df565b909350915060005b8a811015610aaf5760005b89811015610aa6578c8c8381811061095f5761095f6136df565b905060200201602081019061097491906135c3565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156109ff57508a8a828181106109bb576109bb6136df565b90506020020160208101906109d091906135c3565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16145b15610a9e576040518060600160405280888581518110610a2157610a216136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff16815250888781518110610a8c57610a8c6136df565b60200260200101819052508560010195505b600101610945565b5060010161093a565b50600101610914565b508267ffffffffffffffff811115610ad257610ad26130d9565b604051908082528060200260200182016040528015610b3b57816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181610af05790505b50955060005b83811015610b8857858181518110610b5b57610b5b6136df565b6020026020010151878281518110610b7557610b756136df565b6020908102919091010152600101610b41565b505050505050949350505050565b6060600080610bc685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff611d72565b9250925092509250925092565b60606000806106d1610be587876110c9565b85611311565b6060610bfc6103c98686868661086f565b95945050505050565b6060600080835160020267ffffffffffffffff811115610c2757610c276130d9565b604051908082528060200260200182016040528015610c6057816020015b610c4d612c6c565b815260200190600190039081610c455790505b509050610c9060405180608001604052806000815260200160008152602001600015158152602001600081525090565b610cbd60405180608001604052806000815260200160008152602001600015158152602001600081525090565b60008060005b8851811015610e9057610ce1898281518110610811576108116136df565b8051919650945015610e88578451845160019098019703610d055760008452610d13565b845115610d13578660010196505b610d288982815181106105f9576105f96136df565b8093508194505050604051806040016040528060405180606001604052808c8581518110610d5857610d586136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff16815250815260200186815250868260020281518110610dcf57610dcf6136df565b6020026020010181905250604051806040016040528060405180606001604052808c8581518110610e0257610e026136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff16815250815260200185815250868260020260010181518110610e7c57610e7c6136df565b60200260200101819052505b600101610cc3565b50610e9b85876123a3565b98975050505050505050565b6060600080835167ffffffffffffffff811115610ec657610ec66130d9565b604051908082528060200260200182016040528015610eff57816020015b610eec612c6c565b815260200190600190039081610ee45790505b509050610f2f60405180608001604052806000815260200160008152602001600015158152602001600081525090565b610f5c60405180608001604052806000815260200160008152602001600015158152602001600081525090565b610f64612c6c565b60005b875181101561109b57610f85888281518110610811576108116136df565b8094508195505050604051806040016040528060405180606001604052808b8581518110610fb557610fb56136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815250815260200161101f868661247f565b9052602081015151909250156110935785600101955061104a8882815181106105f9576105f96136df565b835173ffffffffffffffffffffffffffffffffffffffff9182166040820152911660209091015284518290869083908110611087576110876136df565b60200260200101819052505b600101610f67565b506110a684866123a3565b979650505050505050565b60606110c06103e4848461157f565b90505b92915050565b60606110c06103c9848461157f565b60006060816110ea60208701876135c3565b73ffffffffffffffffffffffffffffffffffffffff161480611120575073ffffffffffffffffffffffffffffffffffffffff8416155b15611157576040517ff267e74000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620f42408310158061116b57506060850135155b8061117857506080850135155b156111af576040517fb55de08000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060608601356111cc6080880135670de0b6b3a7640000613775565b6111d6919061378c565b9050620f42406111e685826137c7565b6111f09083613775565b6111fa919061378c565b905061120960208701876135c3565b507f8433ea22000000000000000000000000000000000000000000000000000000006060870135828761124260c08b0160a08c016137da565b6040516024810194909452604484019290925273ffffffffffffffffffffffffffffffffffffffff1660648301521515608482015260a401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529250611306908701876135c3565b925050935093915050565b6060600080610bc6857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86611d72565b61136e60405180608001604052806000815260200160008152602001600015158152602001600081525090565b61139b60405180608001604052806000815260200160008152602001600015158152602001600081525090565b6040517f1fcd364900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152600060248301819052917f000000000000000000000000d6c90a7b61f3e0ac04e2f4b0359ab0ac0903550790911690631fcd364990604401610140604051808303816000875af1158015611436573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145a9190613812565b905060405180608001604052808260a0015181526020018260c0015181526020016000151581526020016114968360a001518460c00151612500565b815250925060405180608001604052808260e00151815260200182610100015181526020016001151581526020016114d78360e00151846101000151612500565b815250915050915091565b6114ea612c6c565b73ffffffffffffffffffffffffffffffffffffffff821661150a57919050565b60008061151684611ce7565b9150915060008061152686611341565b6040805160a08101825273ffffffffffffffffffffffffffffffffffffffff808b16928201928352888116606083015287166080820152908152919350915060208101611573848461247f565b90529695505050505050565b6060600061158b611c29565b9050600080825167ffffffffffffffff8111156115aa576115aa6130d9565b6040519080825280602002602001820160405280156115d3578160200160208202803683370190505b50905060008060005b85518110156116c4576115fa8682815181106105f9576105f96136df565b909350915073ffffffffffffffffffffffffffffffffffffffff808416908a1614801561165257508773ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b156116b457858181518110611669576116696136df565b6020026020010151848681518110611683576116836136df565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526116b18561373d565b94505b6116bd8161373d565b90506115dc565b508367ffffffffffffffff8111156116de576116de6130d9565b60405190808252806020026020018201604052801561174757816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816116fc5790505b50955060005b848110156117f9576040518060600160405280858381518110611772576117726136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681526020018a73ffffffffffffffffffffffffffffffffffffffff1681526020018973ffffffffffffffffffffffffffffffffffffffff168152508782815181106117dd576117dd6136df565b6020026020010181905250806117f29061373d565b905061174d565b50505050505092915050565b6060610bfc6103e48686868661086f565b60606000825160020267ffffffffffffffff811115611837576118376130d9565b60405190808252806020026020018201604052801561187057816020015b61185d612c6c565b8152602001906001900390816118555790505b50905060006118a260405180608001604052806000815260200160008152602001600015158152602001600081525090565b6118cf60405180608001604052806000815260200160008152602001600015158152602001600081525090565b60005b86518110156119db576119018782815181106118f0576118f06136df565b602002602001015160000151611341565b80519194509250156119d35782518251600190950194036119255760008252611933565b825115611933578360010193505b6040518060400160405280888381518110611950576119506136df565b6020026020010151815260200184815250858260020281518110611976576119766136df565b6020026020010181905250604051806040016040528088838151811061199e5761199e6136df565b60200260200101518152602001838152508582600202600101815181106119c7576119c76136df565b60200260200101819052505b6001016118d2565b508267ffffffffffffffff8111156119f5576119f56130d9565b604051908082528060200260200182016040528015611a2e57816020015b611a1b612c6c565b815260200190600190039081611a135790505b5094506000805b8551811015611aae576000868281518110611a5257611a526136df565b602002602001015160200151600001511115611aa657858181518110611a7a57611a7a6136df565b6020026020010151878381518110611a9457611a946136df565b60200260200101819052508160010191505b600101611a35565b505050505050919050565b60606103f6610296611c29565b60606000825167ffffffffffffffff811115611ae457611ae46130d9565b604051908082528060200260200182016040528015611b1d57816020015b611b0a612c6c565b815260200190600190039081611b025790505b5090506000611b2a612c6c565b611b5760405180608001604052806000815260200160008152602001600015158152602001600081525090565b611b8460405180608001604052806000815260200160008152602001600015158152602001600081525090565b60005b8751811015611c1e57611ba58882815181106118f0576118f06136df565b80935081945050506040518060400160405280898381518110611bca57611bca6136df565b60200260200101518152602001611be1858561247f565b905260208101515190945015611c165784600101945083868281518110611c0a57611c0a6136df565b60200260200101819052505b600101611b87565b506110a685856123a3565b60606103f67f000000000000000000000000d6c90a7b61f3e0ac04e2f4b0359ab0ac0903550773ffffffffffffffffffffffffffffffffffffffff1663a8d9f4936040518163ffffffff1660e01b8152600401600060405180830381865afa158015611c99573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cdf91908101906138bf565b612710612533565b60008060008373ffffffffffffffffffffffffffffffffffffffff1663b7791bf26040518163ffffffff1660e01b81526004016101a060405180830381865afa158015611d38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d5c919061395f565b90508060a0015181608001519250925050915091565b6060600080611d8086612768565b9550611d8d8686866128b9565b9194509250905084821180611da157508381115b156106d857600060018451611db691906137c7565b9050600086841115611e0b57611dcc87856137c7565b858381518110611dde57611dde6136df565b602002602001015160200151600001516001611dfa9190613a3c565b611e0491906137c7565b905061209a565b6000611e1787856137c7565b868481518110611e2957611e296136df565b60200260200101516020015160200151611e4391906137c7565b905060007f000000000000000000000000d6c90a7b61f3e0ac04e2f4b0359ab0ac0903550773ffffffffffffffffffffffffffffffffffffffff16631fcd3649888681518110611e9557611e956136df565b602090810291909101015151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260006024820152604401610140604051808303816000875af1158015611f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f399190613812565b90506000611f4f8260a001518360c00151612500565b90506000611f848360a001518460e00151611f6a91906137c7565b8460c00151856101000151611f7f91906137c7565b612500565b905081811180611f975750838360c00151105b156120665760008360c00151846101000151611fb391906137c7565b9050848110611fef5781611fd3866b033b2e3c9fd0803ce8000000613775565b611fdd919061378c565b611fe8906001613a3c565b9550612060565b81612006826b033b2e3c9fd0803ce8000000613775565b612010919061378c565b61201b906001613a3c565b95508261202882876137c7565b61203e906b033b2e3c9fd0803ce8000000613775565b612048919061378c565b612053906001613a3c565b61205d9087613a3c565b95505b50612095565b8161207d856b033b2e3c9fd0803ce8000000613775565b612087919061378c565b612092906001613a3c565b94505b505050505b60007f000000000000000000000000d6c90a7b61f3e0ac04e2f4b0359ab0ac0903550773ffffffffffffffffffffffffffffffffffffffff16631fcd36498785815181106120ea576120ea6136df565b602090810291909101015151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101859052604401610140604051808303816000875af115801561216a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218e9190613812565b90508583815181106121a2576121a26136df565b60200260200101516020015160000151856121bd91906137c7565b94508583815181106121d1576121d16136df565b60200260200101516020015160200151846121ec91906137c7565b9350858381518110612200576122006136df565b60200260200101516020015160400151156122aa578060e0015186848151811061222c5761222c6136df565b6020026020010151602001516000018181525050806101000151868481518110612258576122586136df565b602002602001015160200151602001818152505061227f8160e00151826101000151612500565b868481518110612291576122916136df565b6020026020010151602001516060018181525050612339565b8060a001518684815181106122c1576122c16136df565b60200260200101516020015160000181815250508060c001518684815181106122ec576122ec6136df565b60200260200101516020015160200181815250506123128160a001518260c00151612500565b868481518110612324576123246136df565b60200260200101516020015160600181815250505b85838151811061234b5761234b6136df565b60200260200101516020015160000151856123669190613a3c565b945085838151811061237a5761237a6136df565b60200260200101516020015160200151846123959190613a3c565b935050505093509350939050565b60608167ffffffffffffffff8111156123be576123be6130d9565b6040519080825280602002602001820160405280156123f757816020015b6123e4612c6c565b8152602001906001900390816123dc5790505b5090506000805b845181101561247757600085828151811061241b5761241b6136df565b60200260200101516020015160000151111561246f57848181518110612443576124436136df565b602002602001015183838151811061245d5761245d6136df565b60200260200101819052508160010191505b6001016123fe565b505092915050565b6124ac60405180608001604052806000815260200160008152602001600015158152602001600081525090565b81516000036124bc5750806110c3565b8260600151826060015111156124d35750806110c3565b82606001518260600151036124f95782518251036124f25750816110c3565b50806110c3565b5090919050565b600081600003612512575060006110c3565b82612529836b033b2e3c9fd0803ce8000000613775565b6110c0919061378c565b8151606090600090815b855181101561264957858181518110612558576125586136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1663bb24fe8a6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156125e4575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526125e191810190613a4f565b60015b6125f25761271092506125f5565b92505b848314612641576000868281518110612610576126106136df565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261263e82613a68565b91505b60010161253d565b508067ffffffffffffffff811115612663576126636130d9565b60405190808252806020026020018201604052801561268c578160200160208202803683370190505b5092506000805b865181101561275e57600073ffffffffffffffffffffffffffffffffffffffff168782815181106126c6576126c66136df565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614612756578681815181106126fb576126fb6136df565b6020026020010151858381518110612715576127156136df565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508160010191505b600101612693565b5050505092915050565b60606000612774612c6c565b60015b84518110156128b0576000925060005b81865161279491906137c7565b81101561288f578581815181106127ad576127ad6136df565b60200260200101516020015160600151868260016127cb9190613a3c565b815181106127db576127db6136df565b60200260200101516020015160600151111561287d57858181518110612803576128036136df565b602002602001015192508581600161281b9190613a3c565b8151811061282b5761282b6136df565b6020026020010151868281518110612845576128456136df565b6020908102919091010152828661285d836001613a3c565b8151811061286d5761286d6136df565b6020026020010181905250600193505b806128878161373d565b915050612787565b508261289e5750929392505050565b806128a88161373d565b915050612777565b50929392505050565b606060008085516000036128d5575084915060009050806106d8565b60005b85831080156128e657508482105b80156128f25750865181105b1561296557868181518110612909576129096136df565b60200260200101516020015160000151836129249190613a3c565b9250868181518110612938576129386136df565b60200260200101516020015160200151826129539190613a3c565b915061295e8161373d565b90506128d8565b6000805b6129746001846137c7565b811015612aaa576000612988826001613a3c565b90505b83811015612a99578981815181106129a5576129a56136df565b6020026020010151600001516000015173ffffffffffffffffffffffffffffffffffffffff168a83815181106129dd576129dd6136df565b6020026020010151600001516000015173ffffffffffffffffffffffffffffffffffffffff1603612a8957898281518110612a1a57612a1a6136df565b6020026020010151602001516040015115612a575760008a8281518110612a4357612a436136df565b602090810291909101810151015152612a7b565b60008a8381518110612a6b57612a6b6136df565b6020908102919091018101510151525b82612a858161373d565b9350505b612a928161373d565b905061298b565b50612aa38161373d565b9050612969565b508015612bb8576000818951612ac091906137c7565b67ffffffffffffffff811115612ad857612ad86130d9565b604051908082528060200260200182016040528015612b1157816020015b612afe612c6c565b815260200190600190039081612af65790505b50955060005b8951811015612b9e5760008a8281518110612b3457612b346136df565b602002602001015160200151600001511115612b8e57898181518110612b5c57612b5c6136df565b6020026020010151878381518110612b7657612b766136df565b602002602001018190525081612b8b9061373d565b91505b612b978161373d565b9050612b17565b50612baa8689896128b9565b9550955095505050506106d8565b8167ffffffffffffffff811115612bd157612bd16130d9565b604051908082528060200260200182016040528015612c0a57816020015b612bf7612c6c565b815260200190600190039081612bef5790505b50945060005b82811015612c6057888181518110612c2a57612c2a6136df565b6020026020010151868281518110612c4457612c446136df565b602002602001018190525080612c599061373d565b9050612c10565b50505093509350939050565b6040805160a08101825260009181018281526060820183905260808201929092529081908152602001612cc260405180608001604052806000815260200160008152602001600015158152602001600081525090565b905290565b612d01828251805173ffffffffffffffffffffffffffffffffffffffff908116835260208083015182169084015260409182015116910152565b6020810151612d3660608401828051825260208101516020830152604081015115156040830152606081015160608301525050565b505050565b600081518084526020808501945080840160005b83811015612d7557612d62878351612cc7565b60e0969096019590820190600101612d4f565b509495945050505050565b6020815260006110c06020830184612d3b565b73ffffffffffffffffffffffffffffffffffffffff81168114612db557600080fd5b50565b60008060008060608587031215612dce57600080fd5b843567ffffffffffffffff80821115612de657600080fd5b818701915087601f830112612dfa57600080fd5b813581811115612e0957600080fd5b88602060e083028501011115612e1e57600080fd5b60209283019650945050850135612e3481612d93565b9396929550929360400135925050565b6000815180845260005b81811015612e6a57602081850181015186830182015201612e4e565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b604080825283519082018190526000906020906060840190828701845b82811015612ef757815173ffffffffffffffffffffffffffffffffffffffff1684529284019290840190600101612ec5565b50505083810382850152845180825282820190600581901b8301840187850160005b83811015612f65577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018552612f53838351612e44565b94870194925090860190600101612f19565b50909998505050505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612fe557612fd2838551805173ffffffffffffffffffffffffffffffffffffffff908116835260208083015182169084015260409182015116910152565b9284019260609290920191600101612f90565b50909695505050505050565b60008060006060848603121561300657600080fd5b833561301181612d93565b9250602084013561302181612d93565b929592945050506040919091013590565b6060815260006130456060830186612d3b565b60208301949094525060400152919050565b600081518084526020808501945080840160005b83811015612d75576130a18783518051825260208101516020830152604081015115156040830152606081015160608301525050565b608096909601959082019060010161306b565b6040815260006130c76040830185613057565b8281036020840152610bfc8185613057565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561312b5761312b6130d9565b60405290565b6040516080810167ffffffffffffffff8111828210171561312b5761312b6130d9565b604051610140810167ffffffffffffffff8111828210171561312b5761312b6130d9565b6040516101a0810167ffffffffffffffff8111828210171561312b5761312b6130d9565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156131e3576131e36130d9565b604052919050565b600067ffffffffffffffff821115613205576132056130d9565b5060051b60200190565b6000602080838503121561322257600080fd5b823567ffffffffffffffff81111561323957600080fd5b8301601f8101851361324a57600080fd5b803561325d613258826131eb565b61319c565b81815260059190911b8201830190838101908783111561327c57600080fd5b928401925b828410156110a657833561329481612d93565b82529284019290840190613281565b60008083601f8401126132b557600080fd5b50813567ffffffffffffffff8111156132cd57600080fd5b6020830191508360208260051b85010111156132e857600080fd5b9250929050565b6000806000806040858703121561330557600080fd5b843567ffffffffffffffff8082111561331d57600080fd5b613329888389016132a3565b9096509450602087013591508082111561334257600080fd5b5061334f878288016132a3565b95989497509550505050565b60006060828403121561336d57600080fd5b6040516060810181811067ffffffffffffffff82111715613390576133906130d9565b60405290508082356133a181612d93565b815260208301356133b181612d93565b602082015260408301356133c481612d93565b6040919091015292915050565b8015158114612db557600080fd5b60008060408084860312156133f357600080fd5b833567ffffffffffffffff81111561340a57600080fd5b8401601f8101861361341b57600080fd5b8035602061342b613258836131eb565b82815260e0928302840182019282820191908a85111561344a57600080fd5b948301945b848610156134f957858b03818112156134685760008081fd5b613470613108565b61347a8d8961335b565b815260606080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0850112156134b05760008081fd5b6134b8613131565b8a8301358152908a013588820152925060a08901356134d6816133d1565b838b015260c089013590830152808601919091528352948501949183019161344f565b509997909101359750505050505050565b6000806040838503121561351d57600080fd5b823561352881612d93565b9150602083013561353881612d93565b809150509250929050565b600080600083850361012081121561355a57600080fd5b60e081121561356857600080fd5b5083925060e084013561357a81612d93565b92959294505050610100919091013590565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006135bb6040830184612e44565b949350505050565b6000602082840312156135d557600080fd5b81356135e081612d93565b9392505050565b825181526020808401518183015260408085015115158184015260608086015181850152845160808501529184015160a0840152830151151560c083015282015160e082015261010081016135e0565b60e081016110c38284612cc7565b6000602080838503121561365857600080fd5b823567ffffffffffffffff81111561366f57600080fd5b8301601f8101851361368057600080fd5b803561368e613258826131eb565b818152606091820283018401918482019190888411156136ad57600080fd5b938501935b838510156136d3576136c4898661335b565b835293840193918501916136b2565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361376e5761376e61370e565b5060010190565b80820281158282048414176110c3576110c361370e565b6000826137c2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156110c3576110c361370e565b6000602082840312156137ec57600080fd5b81356135e0816133d1565b805161380281612d93565b919050565b8051613802816133d1565b6000610140828403121561382557600080fd5b61382d613154565b613836836137f7565b8152613844602084016137f7565b6020820152613855604084016137f7565b6040820152613866606084016137f7565b6060820152613877608084016137f7565b608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206138b4818501613807565b908201529392505050565b600060208083850312156138d257600080fd5b825167ffffffffffffffff8111156138e957600080fd5b8301601f810185136138fa57600080fd5b8051613908613258826131eb565b81815260059190911b8201830190838101908783111561392757600080fd5b928401925b828410156110a657835161393f81612d93565b8252928401929084019061392c565b805160ff8116811461380257600080fd5b60006101a0828403121561397257600080fd5b61397a613178565b613983836137f7565b8152613991602084016137f7565b60208201526139a2604084016137f7565b60408201526139b3606084016137f7565b60608201526139c4608084016137f7565b60808201526139d560a084016137f7565b60a08201526139e660c0840161394e565b60c08201526139f760e0840161394e565b60e08201526101008381015190820152610120808401519082015261014080840151908201526101608084015190820152610180928301519281019290925250919050565b808201808211156110c3576110c361370e565b600060208284031215613a6157600080fd5b5051919050565b600081613a7757613a7761370e565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea26469706673582212204a67e6a867ff566c7338aa7dab6c38751989ef164ccdf002c8b4f95df5935e0064736f6c63430008150033

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

000000000000000000000000d6c90a7b61f3e0ac04e2f4b0359ab0ac09035507

-----Decoded View---------------
Arg [0] : vaultResolver_ (address): 0xd6C90A7B61F3e0Ac04e2F4B0359aB0ac09035507

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d6c90a7b61f3e0ac04e2f4b0359ab0ac09035507


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.