ETH Price: $1,830.60 (-1.10%)

Contract

0xAa7584C7d375694B4351e520Af1097D9a36fCee2
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CrossChainDispatcher

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion, MIT license
File 1 of 39 : CrossChainDispatcher.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./utils/ReentrancyGuard.sol";
import "./dependencies/@layerzerolabs/solidity-examples/util/BytesLib.sol";
import "./dependencies/openzeppelin/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/external/IStargateComposerWithRetry.sol";
import "./interfaces/external/IWETH.sol";
import "./interfaces/external/IStargatePool.sol";
import "./interfaces/external/IStargateFactory.sol";
import "./storage/CrossChainDispatcherStorage.sol";
import "./interfaces/IProxyOFT.sol";
import "./interfaces/ISmartFarmingManager.sol";
import "./interfaces/ISyntheticToken.sol";
import "./interfaces/external/ISwapper.sol";
import "./lib/CrossChainLib.sol";

error AddressIsNull();
error InvalidMsgSender();
error BridgingIsPaused();
error InvalidFromAddress();
error InvalidToAddress();
error NewValueIsSameAsCurrent();
error SenderIsNotGovernor();
error DestinationChainNotAllowed();
error InvalidOperationType();
error InvalidCallData();
error InvalidPayload();

/**
 * @title Cross-chain dispatcher
 */
contract CrossChainDispatcher is ReentrancyGuard, CrossChainDispatcherStorageV1 {
    using SafeERC20 for IERC20;
    using BytesLib for bytes;

    string public constant VERSION = "1.3.0";

    /**
     * @dev LayerZero adapter param version
     * See more: https://layerzero.gitbook.io/docs/evm-guides/advanced/relayer-adapter-parameters
     */
    uint16 private constant LZ_ADAPTER_PARAMS_VERSION = 2;

    uint256 private constant MAX_BPS = 100_00;

    struct LayerZeroParams {
        address tokenIn;
        uint16 dstChainId;
        uint256 amountIn;
        uint256 nativeFee;
        bytes payload;
        address refundAddress;
        uint64 dstGasForCall;
        uint256 dstNativeAmount;
    }

    /// @notice Emitted when Lz base gas limit updated
    event LzBaseGasLimitUpdated(uint256 oldLzBaseGasLimit, uint256 newLzBaseGasLimit);

    /// @notice Emitted when Stargate composer is updated
    event StargateComposerUpdated(IStargateComposer oldStargateComposer, IStargateComposer newStargateComposer);

    /// @notice Emitted when Stargate pool id is updated
    event StargatePoolIdUpdated(address indexed token, uint256 oldPoolId, uint256 newPoolId);

    /// @notice Emitted when Stargate slippage is updated
    event StargateSlippageUpdated(uint256 oldStargateSlippage, uint256 newStargateSlippage);

    /// @notice Emitted when synth->underlying L1 swap gas limit is updated
    event LeverageSwapTxGasLimitUpdated(uint64 oldSwapTxGasLimit, uint64 newSwapTxGasLimit);

    /// @notice Emitted when leverage callback gas limit is updated
    event LeverageCallbackTxGasLimitUpdated(uint64 oldCallbackTxGasLimit, uint64 newCallbackTxGasLimit);

    /// @notice Emitted when underlying->synth L1 swap gas limit is updated
    event FlashRepaySwapTxGasLimitUpdated(uint64 oldSwapTxGasLimit, uint64 newSwapTxGasLimit);

    /// @notice Emitted when flash repay callback gas limit is updated
    event FlashRepayCallbackTxGasLimitUpdated(uint64 oldCallbackTxGasLimit, uint64 newCallbackTxGasLimit);

    /// @notice Emitted when flag for pause bridge transfer is toggled
    event BridgingIsActiveUpdated(bool newIsActive);

    /// @notice Emitted when a Cross-chain dispatcher mapping is updated
    event CrossChainDispatcherUpdated(uint16 chainId, address oldCrossChainDispatcher, address newCrossChainDispatcher);

    /// @notice Emitted when flag for support chain is toggled
    event DestinationChainIsSupportedUpdated(uint16 chainId, bool newIsSupported);

    modifier onlyGovernor() {
        if (msg.sender != poolRegistry.governor()) revert SenderIsNotGovernor();
        _;
    }

    modifier onlyIfBridgingIsNotPaused() {
        if (!isBridgingActive) revert BridgingIsPaused();
        _;
    }

    modifier onlyIfSmartFarmingManager() {
        IPool _pool = IManageable(msg.sender).pool();
        if (!poolRegistry.isPoolRegistered(address(_pool))) revert InvalidMsgSender();
        if (msg.sender != address(_pool.smartFarmingManager())) revert InvalidMsgSender();
        _;
    }

    modifier onlyIfStargateComposer() {
        if (msg.sender != address(stargateComposer)) revert InvalidMsgSender();
        _;
    }

    modifier onlyIfProxyOFT() {
        if (!_isValidProxyOFT(msg.sender)) revert InvalidMsgSender();
        _;
    }

    constructor() {
        _disableInitializers();
    }

    receive() external payable {}

    function initialize(IPoolRegistry poolRegistry_, address weth_, address sgeth_) external initializer {
        if (address(poolRegistry_) == address(0)) revert AddressIsNull();

        __ReentrancyGuard_init();

        poolRegistry = poolRegistry_;
        stargateSlippage = 50; // 0.5%
        lzBaseGasLimit = 200_000;
        flashRepayCallbackTxGasLimit = 750_000;
        flashRepaySwapTxGasLimit = 500_000;
        leverageCallbackTxGasLimit = 750_000;
        leverageSwapTxGasLimit = 750_000;
        weth = weth_;
        sgeth = sgeth_;
    }

    /**
     * @notice Called by the OFT contract when tokens are received from source chain.
     * @dev Token received are swapped to another token
     * @param srcChainId_ The chain id of the source chain.
     * @param from_ The address of the account who calls the sendAndCall() on the source chain.
     * @param amount_ The amount of tokens to transfer.
     * @param payload_ Additional data with no specified format.
     */
    function onOFTReceived(
        uint16 srcChainId_,
        bytes calldata /*srcAddress_*/,
        uint64 /*nonce_*/,
        bytes calldata from_,
        uint amount_,
        bytes calldata payload_
    ) external override onlyIfProxyOFT {
        address _from = from_.toAddress(0);
        if (_from == address(0) || _from != crossChainDispatcherOf[srcChainId_]) revert InvalidFromAddress();

        uint8 _op = CrossChainLib.getOperationType(payload_);

        if (_op == CrossChainLib.FLASH_REPAY) {
            _crossChainFlashRepayCallback(amount_, payload_);
        } else if (_op == CrossChainLib.LEVERAGE) {
            _swapAndTriggerLeverageCallback(srcChainId_, amount_, payload_);
        } else {
            revert InvalidOperationType();
        }
    }

    /**
     * @dev Finalize cross-chain flash repay process. The callback may fail due to slippage.
     */
    function _crossChainFlashRepayCallback(uint amount_, bytes calldata payload_) private {
        (address proxyOFT_, address _smartFarmingManager, uint256 _requestId) = CrossChainLib
            .decodeFlashRepayCallbackPayload(payload_);

        IERC20 _syntheticToken = IERC20(IProxyOFT(proxyOFT_).token());
        _syntheticToken.safeApprove(_smartFarmingManager, 0);
        _syntheticToken.safeApprove(_smartFarmingManager, amount_);
        ISmartFarmingManager(_smartFarmingManager).crossChainFlashRepayCallback(_requestId, amount_);
    }

    /**
     * @dev Swap synthetic token for underlying and trigger callback call
     */
    function _swapAndTriggerLeverageCallback(uint16 srcChainId_, uint amountIn_, bytes calldata payload_) private {
        // 1. Swap
        (
            address _srcSmartFarmingManager,
            address _dstProxyOFT,
            uint256 _requestId,
            uint256 _underlyingPoolId,
            address _account,
            uint256 _amountOutMin
        ) = CrossChainLib.decodeLeverageSwapPayload(payload_);

        address _underlying = IStargatePool(IStargateFactory(stargateComposer.factory()).getPool(_underlyingPoolId))
            .token();

        if (_underlying == sgeth) _underlying = weth;

        amountIn_ = _swap({
            requestId_: _requestId,
            tokenIn_: IProxyOFT(_dstProxyOFT).token(),
            tokenOut_: _underlying,
            amountIn_: amountIn_,
            amountOutMin_: _amountOutMin
        });

        // 2. Transfer underlying to source chain
        uint16 _srcChainId = srcChainId_;

        _sendUsingStargate(
            LayerZeroParams({
                tokenIn: _underlying,
                dstChainId: _srcChainId,
                amountIn: amountIn_,
                nativeFee: poolRegistry.quoter().quoteLeverageCallbackNativeFee(_srcChainId),
                payload: CrossChainLib.encodeLeverageCallbackPayload(_srcSmartFarmingManager, _requestId),
                refundAddress: _account,
                dstGasForCall: leverageCallbackTxGasLimit,
                dstNativeAmount: 0
            })
        );
    }

    /**
     * @notice Receive token and payload from Stargate
     * @param srcChainId_ The chain id of the source chain.
     * @param srcAddress_ The remote Bridge address
     * @param token_ The token contract on the local chain
     * @param amountLD_ The qty of local _token contract tokens
     * @param payload_ The payload
     */
    function sgReceive(
        uint16 srcChainId_,
        bytes memory srcAddress_,
        uint256 /*nonce_*/,
        address token_,
        uint256 amountLD_,
        bytes memory payload_
    ) external override onlyIfStargateComposer {
        // Note: Stargate uses SGETH as `token_` when receiving native ETH
        if (token_ == sgeth) {
            IWETH(weth).deposit{value: amountLD_}();
            token_ = weth;
        }

        address _srcAddress = srcAddress_.toAddress(0);

        if (_srcAddress == address(0) || _srcAddress != crossChainDispatcherOf[srcChainId_])
            revert InvalidFromAddress();

        uint8 _op = CrossChainLib.getOperationType(payload_);

        if (_op == CrossChainLib.LEVERAGE) {
            _crossChainLeverageCallback(token_, amountLD_, payload_);
        } else if (_op == CrossChainLib.FLASH_REPAY) {
            _swapAndTriggerFlashRepayCallback(srcChainId_, token_, amountLD_, payload_);
        } else {
            revert InvalidOperationType();
        }
    }

    /**
     * @dev Finalize cross-chain leverage process. The callback may fail due to slippage.
     */
    function _crossChainLeverageCallback(address token_, uint256 amount_, bytes memory payload_) private {
        (address _smartFarmingManager, uint256 _requestId) = CrossChainLib.decodeLeverageCallbackPayload(payload_);
        IERC20(token_).safeApprove(_smartFarmingManager, 0);
        IERC20(token_).safeApprove(_smartFarmingManager, amount_);
        ISmartFarmingManager(_smartFarmingManager).crossChainLeverageCallback(_requestId, amount_);
    }

    /**
     * @dev Send synthetic token cross-chain
     */
    function _sendUsingLayerZero(LayerZeroParams memory params_) private {
        address _to = crossChainDispatcherOf[params_.dstChainId];
        if (_to == address(0)) revert AddressIsNull();

        bytes memory _adapterParams = abi.encodePacked(
            LZ_ADAPTER_PARAMS_VERSION,
            uint256(lzBaseGasLimit + params_.dstGasForCall),
            params_.dstNativeAmount,
            (params_.dstNativeAmount > 0) ? _to : address(0)
        );

        ISyntheticToken(params_.tokenIn).proxyOFT().sendAndCall{value: params_.nativeFee}({
            _from: address(this),
            _dstChainId: params_.dstChainId,
            _toAddress: abi.encodePacked(_to),
            _amount: params_.amountIn,
            _payload: params_.payload,
            _dstGasForCall: params_.dstGasForCall,
            _refundAddress: payable(params_.refundAddress),
            _zroPaymentAddress: address(0),
            _adapterParams: _adapterParams
        });
    }

    /**
     * @dev Swap underlying for synthetic token and trigger callback call
     */
    function _swapAndTriggerFlashRepayCallback(
        uint16 srcChainId_,
        address token_,
        uint256 amount_,
        bytes memory payload_
    ) private {
        // 1. Swap
        (
            address _srcSmartFarmingManager,
            address _dstProxyOFT,
            uint256 _requestId,
            address _account,
            uint256 _amountOutMin
        ) = CrossChainLib.decodeFlashRepaySwapPayload(payload_);

        address _syntheticToken = IProxyOFT(_dstProxyOFT).token();
        amount_ = _swap({
            requestId_: _requestId,
            tokenIn_: token_,
            tokenOut_: _syntheticToken,
            amountIn_: amount_,
            amountOutMin_: _amountOutMin
        });

        // 2. Transfer synthetic token to source chain
        uint16 _srcChainId = srcChainId_;
        address _srcProxyOFT = IProxyOFT(_dstProxyOFT).getProxyOFTOf(_srcChainId);

        _sendUsingLayerZero(
            LayerZeroParams({
                tokenIn: _syntheticToken,
                dstChainId: _srcChainId,
                amountIn: amount_,
                payload: CrossChainLib.encodeFlashRepayCallbackPayload(
                    _srcProxyOFT,
                    _srcSmartFarmingManager,
                    _requestId
                ),
                refundAddress: _account,
                dstGasForCall: flashRepayCallbackTxGasLimit,
                dstNativeAmount: 0,
                nativeFee: poolRegistry.quoter().quoteFlashRepayCallbackNativeFee(_srcChainId)
            })
        );
    }

    /**
     * @notice Retry swap underlying and trigger callback.
     * @param srcChainId_ The source chain of failed tx
     * @param srcAddress_ The source path of failed tx
     * @param nonce_ The nonce of failed tx
     * @param token_ The token of failed tx
     * @param amount_ The amountIn of failed tx
     * @param payload_ The payload of failed tx
     * @param newAmountOutMin_ If swap failed due to slippage, caller may send lower newAmountOutMin_
     */
    function retrySwapAndTriggerFlashRepayCallback(
        uint16 srcChainId_,
        bytes calldata srcAddress_,
        uint64 nonce_,
        address token_,
        uint256 amount_,
        bytes calldata payload_,
        uint256 newAmountOutMin_
    ) external nonReentrant {
        IStargateComposerWithRetry _stargateComposer = IStargateComposerWithRetry(address(stargateComposer));

        bytes memory _sgReceiveCallData = abi.encodeWithSelector(
            IStargateReceiver.sgReceive.selector,
            srcChainId_,
            abi.encodePacked(crossChainDispatcherOf[srcChainId_]), // use the caller as the srcAddress (the msg.sender caller the StargateComposer at the source)
            nonce_,
            token_,
            amount_,
            payload_
        );

        bytes32 _hash = keccak256(abi.encodePacked(address(this), _sgReceiveCallData));

        if (_hash != _stargateComposer.payloadHashes(srcChainId_, srcAddress_, nonce_)) revert InvalidCallData();

        (, , uint256 _requestId, address _account, ) = CrossChainLib.decodeFlashRepaySwapPayload(payload_);

        if (msg.sender != _account) revert InvalidMsgSender();

        swapAmountOutMin[_requestId] = newAmountOutMin_;

        _stargateComposer.clearCachedSwap(srcChainId_, srcAddress_, nonce_, address(this), _sgReceiveCallData);
    }

    /**
     * @notice Retry swap and trigger callback.
     * @param srcChainId_ The source chain of failed tx
     * @param srcAddress_ The source path of failed tx
     * @param nonce_ The nonce of failed tx
     * @param amount_ The amountIn of failed tx
     * @param payload_ The payload of failed tx
     * @param newAmountOutMin_ If swap failed due to slippage, caller may send lower newAmountOutMin_
     */
    function retrySwapAndTriggerLeverageCallback(
        uint16 srcChainId_,
        bytes calldata srcAddress_,
        uint64 nonce_,
        uint256 amount_,
        bytes calldata payload_,
        uint256 newAmountOutMin_
    ) external nonReentrant {
        (, address _dstProxyOFT, uint256 _requestId, , address _account, ) = CrossChainLib.decodeLeverageSwapPayload(
            payload_
        );

        if (!_isValidProxyOFT(_dstProxyOFT)) revert InvalidPayload();
        if (msg.sender != _account) revert InvalidMsgSender();

        swapAmountOutMin[_requestId] = newAmountOutMin_;

        // Note: `retryOFTReceived()` has checks to ensure that the args are consistent
        bytes memory _from = abi.encodePacked(crossChainDispatcherOf[srcChainId_]);
        IProxyOFT(_dstProxyOFT).retryOFTReceived(
            srcChainId_,
            srcAddress_,
            nonce_,
            _from,
            address(this),
            amount_,
            payload_
        );
    }

    /***
     * @notice Trigger swap using Stargate for flashRepay.
     * @param requestId_ Request id.
     * @param account_ User address and also refund address
     * @param tokenIn_ tokenIn
     * @param tokenOut_ tokenOut
     * @param amountIn_ amountIn_
     * @param amountOutMin_ amountOutMin_
     * @param lzArgs_ LayerZero method argument
     */
    function triggerFlashRepaySwap(
        uint256 requestId_,
        address payable account_,
        address tokenIn_,
        address tokenOut_,
        uint256 amountIn_,
        uint256 amountOutMin_,
        bytes calldata lzArgs_
    ) external payable override nonReentrant onlyIfSmartFarmingManager onlyIfBridgingIsNotPaused {
        address _account = account_; // stack too deep

        (uint16 _dstChainId, uint256 callbackTxNativeFee_, uint64 flashRepaySwapTxGasLimit_) = CrossChainLib
            .decodeLzArgs(lzArgs_);

        bytes memory _payload;
        {
            address _dstProxyOFT = ISyntheticToken(tokenOut_).proxyOFT().getProxyOFTOf(_dstChainId);

            if (_dstProxyOFT == address(0)) revert AddressIsNull();
            if (!isDestinationChainSupported[_dstChainId]) revert DestinationChainNotAllowed();

            uint256 _requestId = requestId_; // stack too deep

            _payload = CrossChainLib.encodeFlashRepaySwapPayload({
                srcSmartFarmingManager_: msg.sender,
                dstProxyOFT_: _dstProxyOFT,
                requestId_: _requestId,
                account_: _account,
                amountOutMin_: amountOutMin_
            });
        }

        _sendUsingStargate(
            LayerZeroParams({
                tokenIn: tokenIn_,
                dstChainId: _dstChainId,
                amountIn: amountIn_,
                nativeFee: msg.value,
                payload: _payload,
                refundAddress: _account,
                dstGasForCall: flashRepaySwapTxGasLimit_,
                dstNativeAmount: callbackTxNativeFee_
            })
        );
    }

    /***
     * @notice Send synthetic token and trigger swap at destination chain
     * @dev Not checking if bridging is pause because `ProxyOFT._debitFrom()` does it
     * @param requestId_ Request id.
     * @param account_ User address and also refund address
     * @param tokenOut_ tokenOut
     * @param amountIn_ amountIn
     * @param amountOutMin_ amountOutMin
     * @param lzArgs_ LayerZero method argument
     */
    function triggerLeverageSwap(
        uint256 requestId_,
        address payable account_,
        address tokenIn_,
        address tokenOut_,
        uint256 amountIn_,
        uint256 amountOutMin_,
        bytes calldata lzArgs_
    ) external payable override nonReentrant onlyIfSmartFarmingManager {
        address _account = account_; // stack too deep

        (uint16 _dstChainId, uint256 _callbackTxNativeFee, uint64 _leverageSwapTxGasLimit) = CrossChainLib.decodeLzArgs(
            lzArgs_
        );

        bytes memory _payload;
        {
            address _dstProxyOFT = ISyntheticToken(tokenIn_).proxyOFT().getProxyOFTOf(_dstChainId);

            if (_dstProxyOFT == address(0)) revert AddressIsNull();
            if (!isDestinationChainSupported[_dstChainId]) revert DestinationChainNotAllowed();

            uint256 _requestId = requestId_; // stack too deep
            address _tokenOut = tokenOut_; // stack too deep
            uint256 _amountOutMin = amountOutMin_; // stack too deep

            _payload = CrossChainLib.encodeLeverageSwapPayload({
                srcSmartFarmingManager_: msg.sender,
                dstProxyOFT_: _dstProxyOFT,
                requestId_: _requestId,
                sgPoolId_: stargatePoolIdOf[_tokenOut],
                account_: _account,
                amountOutMin_: _amountOutMin
            });
        }

        _sendUsingLayerZero(
            LayerZeroParams({
                tokenIn: tokenIn_,
                dstChainId: _dstChainId,
                amountIn: amountIn_,
                payload: _payload,
                refundAddress: _account,
                dstGasForCall: _leverageSwapTxGasLimit,
                dstNativeAmount: _callbackTxNativeFee,
                nativeFee: msg.value
            })
        );
    }

    /**
     * @dev Check wether an address is a proxyOFT or not
     */
    function _isValidProxyOFT(address proxyOFT_) private view returns (bool) {
        ISyntheticToken _syntheticToken = ISyntheticToken(IProxyOFT(proxyOFT_).token());
        if (!poolRegistry.doesSyntheticTokenExist(_syntheticToken)) return false;
        if (proxyOFT_ != address(_syntheticToken.proxyOFT())) return false;

        return true;
    }

    /**
     * @dev Send underlying token cross-chain
     */
    function _sendUsingStargate(LayerZeroParams memory params_) private {
        IStargateRouter.lzTxObj memory _lzTxParams;
        bytes memory _to = abi.encodePacked(crossChainDispatcherOf[params_.dstChainId]);
        {
            if (_to.toAddress(0) == address(0)) revert AddressIsNull();

            _lzTxParams = IStargateRouter.lzTxObj({
                dstGasForCall: params_.dstGasForCall,
                dstNativeAmount: params_.dstNativeAmount,
                dstNativeAddr: (params_.dstNativeAmount > 0) ? _to : abi.encode(0)
            });
        }

        uint256 _poolId = stargatePoolIdOf[params_.tokenIn];
        uint256 _amountOutMin = (params_.amountIn * (MAX_BPS - stargateSlippage)) / MAX_BPS;
        bytes memory _payload = params_.payload;

        IStargateComposer _stargateComposer = stargateComposer;

        // Note: StargateComposer only accepts native for ETH pool
        if (params_.tokenIn == weth) {
            IWETH(weth).withdraw(params_.amountIn);
            params_.nativeFee += params_.amountIn;
        } else {
            IERC20(params_.tokenIn).safeApprove(address(_stargateComposer), 0);
            IERC20(params_.tokenIn).safeApprove(address(_stargateComposer), params_.amountIn);
        }

        _stargateComposer.swap{value: params_.nativeFee}({
            _dstChainId: params_.dstChainId,
            _srcPoolId: _poolId,
            _dstPoolId: _poolId,
            _refundAddress: payable(params_.refundAddress),
            _amountLD: params_.amountIn,
            _minAmountLD: _amountOutMin,
            _lzTxParams: _lzTxParams,
            _to: _to,
            _payload: _payload
        });
    }

    /**
     * @dev Perform a swap considering slippage param from user
     */
    function _swap(
        uint256 requestId_,
        address tokenIn_,
        address tokenOut_,
        uint256 amountIn_,
        uint256 amountOutMin_
    ) private returns (uint256 _amountOut) {
        // 1. Use updated slippage if exist
        uint256 _storedAmountOutMin = swapAmountOutMin[requestId_];
        if (_storedAmountOutMin > 0) {
            // Use stored slippage and clear it
            amountOutMin_ = _storedAmountOutMin;
            delete swapAmountOutMin[requestId_];
        }

        // 2. Perform swap
        ISwapper _swapper = poolRegistry.swapper();
        IERC20(tokenIn_).safeApprove(address(_swapper), 0);
        IERC20(tokenIn_).safeApprove(address(_swapper), amountIn_);
        _amountOut = _swapper.swapExactInput({
            tokenIn_: tokenIn_,
            tokenOut_: tokenOut_,
            amountIn_: amountIn_,
            amountOutMin_: amountOutMin_,
            receiver_: address(this)
        });
    }

    /**
     * @notice Update flash repay callback tx gas limit
     */
    function updateFlashRepayCallbackTxGasLimit(uint64 newFlashRepayCallbackTxGasLimit_) external onlyGovernor {
        uint64 _currentFlashRepayCallbackTxGasLimit = flashRepayCallbackTxGasLimit;
        if (newFlashRepayCallbackTxGasLimit_ == _currentFlashRepayCallbackTxGasLimit) revert NewValueIsSameAsCurrent();
        emit FlashRepayCallbackTxGasLimitUpdated(
            _currentFlashRepayCallbackTxGasLimit,
            newFlashRepayCallbackTxGasLimit_
        );
        flashRepayCallbackTxGasLimit = newFlashRepayCallbackTxGasLimit_;
    }

    /**
     * @notice Update flash repay swap tx gas limit
     */
    function updateFlashRepaySwapTxGasLimit(uint64 newFlashRepaySwapTxGasLimit_) external onlyGovernor {
        uint64 _currentFlashRepaySwapTxGasLimit = flashRepaySwapTxGasLimit;
        if (newFlashRepaySwapTxGasLimit_ == _currentFlashRepaySwapTxGasLimit) revert NewValueIsSameAsCurrent();
        emit FlashRepaySwapTxGasLimitUpdated(_currentFlashRepaySwapTxGasLimit, newFlashRepaySwapTxGasLimit_);
        flashRepaySwapTxGasLimit = newFlashRepaySwapTxGasLimit_;
    }

    /**
     * @notice Update leverage callback tx gas limit
     */
    function updateLeverageCallbackTxGasLimit(uint64 newLeverageCallbackTxGasLimit_) external onlyGovernor {
        uint64 _currentLeverageCallbackTxGasLimit = leverageCallbackTxGasLimit;
        if (newLeverageCallbackTxGasLimit_ == _currentLeverageCallbackTxGasLimit) revert NewValueIsSameAsCurrent();
        emit LeverageCallbackTxGasLimitUpdated(_currentLeverageCallbackTxGasLimit, newLeverageCallbackTxGasLimit_);
        leverageCallbackTxGasLimit = newLeverageCallbackTxGasLimit_;
    }

    /**
     * @notice Update leverage swap tx gas limit
     */
    function updateLeverageSwapTxGasLimit(uint64 newLeverageSwapTxGasLimit_) external onlyGovernor {
        uint64 _currentSwapTxGasLimit = leverageSwapTxGasLimit;
        if (newLeverageSwapTxGasLimit_ == _currentSwapTxGasLimit) revert NewValueIsSameAsCurrent();
        emit LeverageSwapTxGasLimitUpdated(_currentSwapTxGasLimit, newLeverageSwapTxGasLimit_);
        leverageSwapTxGasLimit = newLeverageSwapTxGasLimit_;
    }

    /**
     * @notice Update Lz base gas limit
     */
    function updateLzBaseGasLimit(uint256 newLzBaseGasLimit_) external onlyGovernor {
        uint256 _currentBaseGasLimit = lzBaseGasLimit;
        if (newLzBaseGasLimit_ == _currentBaseGasLimit) revert NewValueIsSameAsCurrent();
        emit LzBaseGasLimitUpdated(_currentBaseGasLimit, newLzBaseGasLimit_);
        lzBaseGasLimit = newLzBaseGasLimit_;
    }

    /**
     * @notice Update Stargate pool id of token.
     * @dev Use LZ ids (https://stargateprotocol.gitbook.io/stargate/developers/pool-ids)
     */
    function updateStargatePoolIdOf(address token_, uint256 newPoolId_) external onlyGovernor {
        uint256 _currentPoolId = stargatePoolIdOf[token_];
        if (newPoolId_ == _currentPoolId) revert NewValueIsSameAsCurrent();
        emit StargatePoolIdUpdated(token_, _currentPoolId, newPoolId_);
        stargatePoolIdOf[token_] = newPoolId_;
    }

    /**
     * @notice Update Stargate slippage
     */
    function updateStargateSlippage(uint256 newStargateSlippage_) external onlyGovernor {
        uint256 _currentStargateSlippage = stargateSlippage;
        if (newStargateSlippage_ == _currentStargateSlippage) revert NewValueIsSameAsCurrent();
        emit StargateSlippageUpdated(_currentStargateSlippage, newStargateSlippage_);
        stargateSlippage = newStargateSlippage_;
    }

    /**
     * @notice Update StargateComposer
     */
    function updateStargateComposer(IStargateComposer newStargateComposer_) external onlyGovernor {
        IStargateComposer _currentStargateComposer = stargateComposer;
        if (newStargateComposer_ == _currentStargateComposer) revert NewValueIsSameAsCurrent();
        emit StargateComposerUpdated(_currentStargateComposer, newStargateComposer_);
        stargateComposer = newStargateComposer_;
    }

    /**
     * @notice Pause/Unpause bridge transfers
     */
    function toggleBridgingIsActive() external onlyGovernor {
        bool _newIsBridgingActive = !isBridgingActive;
        emit BridgingIsActiveUpdated(_newIsBridgingActive);
        isBridgingActive = _newIsBridgingActive;
    }

    /**
     * @notice Update Cross-chain dispatcher mapping
     */
    function updateCrossChainDispatcherOf(uint16 chainId_, address crossChainDispatcher_) external onlyGovernor {
        address _current = crossChainDispatcherOf[chainId_];
        if (crossChainDispatcher_ == _current) revert NewValueIsSameAsCurrent();
        emit CrossChainDispatcherUpdated(chainId_, _current, crossChainDispatcher_);
        crossChainDispatcherOf[chainId_] = crossChainDispatcher_;
    }

    /**
     * @notice Allow/Disallow destination chain
     * @dev Use LZ chain id
     */
    function toggleDestinationChainIsActive(uint16 chainId_) external onlyGovernor {
        bool _isDestinationChainSupported = !isDestinationChainSupported[chainId_];
        emit BridgingIsActiveUpdated(_isDestinationChainSupported);
        isDestinationChainSupported[chainId_] = _isDestinationChainSupported;
    }
}

File 2 of 39 : IOFTCoreUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.2;

import "../../../../../openzeppelin-upgradeable/utils/introspection/IERC165Upgradeable.sol";

/**
 * @dev Interface of the IOFT core standard
 */
interface IOFTCoreUpgradeable is IERC165Upgradeable {
    /**
     * @dev estimate send token `_tokenId` to (`_dstChainId`, `_toAddress`)
     * _dstChainId - L0 defined chain id to send tokens too
     * _toAddress - dynamic bytes array which contains the address to whom you are sending tokens to on the dstChain
     * _amount - amount of the tokens to transfer
     * _useZro - indicates to use zro to pay L0 fees
     * _adapterParam - flexible bytes array to indicate messaging adapter services in L0
     */
    function estimateSendFee(
        uint16 _dstChainId,
        bytes calldata _toAddress,
        uint _amount,
        bool _useZro,
        bytes calldata _adapterParams
    ) external view returns (uint nativeFee, uint zroFee);

    /**
     * @dev send `_amount` amount of token to (`_dstChainId`, `_toAddress`) from `_from`
     * `_from` the owner of token
     * `_dstChainId` the destination chain identifier
     * `_toAddress` can be any size depending on the `dstChainId`.
     * `_amount` the quantity of tokens in wei
     * `_refundAddress` the address LayerZero refunds if too much message fee is sent
     * `_zroPaymentAddress` set to address(0x0) if not paying in ZRO (LayerZero Token)
     * `_adapterParams` is a flexible bytes array to indicate messaging adapter services
     */
    function sendFrom(
        address _from,
        uint16 _dstChainId,
        bytes calldata _toAddress,
        uint _amount,
        address payable _refundAddress,
        address _zroPaymentAddress,
        bytes calldata _adapterParams
    ) external payable;

    /**
     * @dev returns the circulating amount of tokens on current chain
     */
    function circulatingSupply() external view returns (uint);

    /**
     * @dev returns the address of the ERC20 token
     */
    function token() external view returns (address);

    /**
     * @dev Emitted when `_amount` tokens are moved from the `_sender` to (`_dstChainId`, `_toAddress`)
     * `_nonce` is the outbound nonce
     */
    event SendToChain(uint16 indexed _dstChainId, address indexed _from, bytes _toAddress, uint _amount);

    /**
     * @dev Emitted when `_amount` tokens are received from `_srcChainId` into the `_toAddress` on the local chain.
     * `_nonce` is the inbound nonce.
     */
    event ReceiveFromChain(uint16 indexed _srcChainId, address indexed _to, uint _amount);

    event SetUseCustomAdapterParams(bool _useCustomAdapterParams);
}

File 3 of 39 : IComposableOFTCoreUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0;

import "../IOFTCoreUpgradeable.sol";

/**
 * @dev Interface of the composable OFT core standard
 */
interface IComposableOFTCoreUpgradeable is IOFTCoreUpgradeable {
    function estimateSendAndCallFee(
        uint16 _dstChainId,
        bytes calldata _toAddress,
        uint _amount,
        bytes calldata _payload,
        uint64 _dstGasForCall,
        bool _useZro,
        bytes calldata _adapterParams
    ) external view returns (uint nativeFee, uint zroFee);

    function sendAndCall(
        address _from,
        uint16 _dstChainId,
        bytes calldata _toAddress,
        uint _amount,
        bytes calldata _payload,
        uint64 _dstGasForCall,
        address payable _refundAddress,
        address _zroPaymentAddress,
        bytes calldata _adapterParams
    ) external payable;

    function retryOFTReceived(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        uint64 _nonce,
        bytes calldata _from,
        address _to,
        uint _amount,
        bytes calldata _payload
    ) external;

    event CallOFTReceivedFailure(
        uint16 indexed _srcChainId,
        bytes _srcAddress,
        uint64 _nonce,
        bytes _from,
        address indexed _to,
        uint _amount,
        bytes _payload,
        bytes _reason
    );

    event CallOFTReceivedSuccess(uint16 indexed _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _hash);

    event RetryOFTReceivedSuccess(bytes32 _messageHash);

    event NonContractAddress(address _address);
}

File 4 of 39 : IOFTReceiverUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0;

interface IOFTReceiverUpgradeable {
    /**
     * @dev Called by the OFT contract when tokens are received from source chain.
     * @param _srcChainId The chain id of the source chain.
     * @param _srcAddress The address of the OFT token contract on the source chain.
     * @param _nonce The nonce of the transaction on the source chain.
     * @param _from The address of the account who calls the sendAndCall() on the source chain.
     * @param _amount The amount of tokens to transfer.
     * @param _payload Additional data with no specified format.
     */
    function onOFTReceived(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        uint64 _nonce,
        bytes calldata _from,
        uint _amount,
        bytes calldata _payload
    ) external;
}

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

library BytesLib {
    function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {
        bytes memory tempBytes;

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

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for {
                let cc := add(_postBytes, 0x20)
            } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                mstore(mc, mload(cc))
            }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(
                0x40,
                and(
                    add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                    not(31) // Round down to the nearest 32 bytes.
                )
            )
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes.slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } {
                    sstore(sc, mload(mc))
                }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

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

        bytes memory tempBytes;

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

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

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

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

                mstore(tempBytes, _length)

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

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

        return tempBytes;
    }

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

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

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1, "toUint8_outOfBounds");
        uint8 tempUint;

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

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

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

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

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

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

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

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

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

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

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

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

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

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for {
                    let cc := add(_postBytes, 0x20)
                    // the next line is the loop condition:
                    // while(uint256(mc < end) + cb == 2)
                } eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        for {

                        } eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}

File 6 of 39 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
     */
    modifier initializer() {
        bool isTopLevelCall = _setInitializedVersion(1);
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
     * initialization step. This is essential to configure modules that are added through upgrades and that require
     * initialization.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     */
    modifier reinitializer(uint8 version) {
        bool isTopLevelCall = _setInitializedVersion(version);
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(version);
        }
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     */
    function _disableInitializers() internal virtual {
        _setInitializedVersion(type(uint8).max);
    }

    function _setInitializedVersion(uint8 version) private returns (bool) {
        // If the contract is initializing we ignore whether _initialized is set in order to support multiple
        // inheritance patterns, but we only do this in the context of a constructor, and for the lowest level
        // of initializers, because in other contexts the contract may have been reentered.
        if (_initializing) {
            require(
                version == 1 && !AddressUpgradeable.isContract(address(this)),
                "Initializable: contract is already initialized"
            );
            return false;
        } else {
            require(_initialized < version, "Initializable: contract is already initialized");
            _initialized = version;
            return true;
        }
    }
}

File 7 of 39 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 8 of 39 : IERC165Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165Upgradeable {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 9 of 39 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 10 of 39 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";

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

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

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

File 11 of 39 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

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

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

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

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

File 12 of 39 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 13 of 39 : IStargateComposer.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.9;

import "./IStargateRouter.sol";

interface IStargateComposer {
    function swap(
        uint16 _dstChainId,
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        address payable _refundAddress,
        uint256 _amountLD,
        uint256 _minAmountLD,
        IStargateRouter.lzTxObj memory _lzTxParams,
        bytes calldata _to,
        bytes calldata _payload
    ) external payable;

    function factory() external view returns (address);

    function stargateBridge() external view returns (address);

    function stargateRouter() external view returns (IStargateRouter);

    function quoteLayerZeroFee(
        uint16 _dstChainId,
        uint8 _functionType,
        bytes calldata _toAddress,
        bytes calldata _transferAndCallPayload,
        IStargateRouter.lzTxObj memory _lzTxParams
    ) external view returns (uint256, uint256);

    function peers(uint16 _chainId) external view returns (address);
}

File 14 of 39 : IStargateReceiver.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.9;

interface IStargateReceiver {
    function sgReceive(
        uint16 _chainId,
        bytes memory _srcAddress,
        uint256 _nonce,
        address _token,
        uint256 amountLD,
        bytes memory payload
    ) external;
}

File 15 of 39 : IStargateRouter.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.9;

interface IStargateRouter {
    struct lzTxObj {
        uint256 dstGasForCall;
        uint256 dstNativeAmount;
        bytes dstNativeAddr;
    }

    function addLiquidity(uint256 _poolId, uint256 _amountLD, address _to) external;

    function swap(
        uint16 _dstChainId,
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        address payable _refundAddress,
        uint256 _amountLD,
        uint256 _minAmountLD,
        lzTxObj memory _lzTxParams,
        bytes calldata _to,
        bytes calldata _payload
    ) external payable;

    function redeemRemote(
        uint16 _dstChainId,
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        address payable _refundAddress,
        uint256 _amountLP,
        uint256 _minAmountLD,
        bytes calldata _to,
        lzTxObj memory _lzTxParams
    ) external payable;

    function instantRedeemLocal(uint16 _srcPoolId, uint256 _amountLP, address _to) external returns (uint256);

    function redeemLocal(
        uint16 _dstChainId,
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        address payable _refundAddress,
        uint256 _amountLP,
        bytes calldata _to,
        lzTxObj memory _lzTxParams
    ) external payable;

    function sendCredits(
        uint16 _dstChainId,
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        address payable _refundAddress
    ) external payable;

    function quoteLayerZeroFee(
        uint16 _dstChainId,
        uint8 _functionType,
        bytes calldata _toAddress,
        bytes calldata _transferAndCallPayload,
        lzTxObj memory _lzTxParams
    ) external view returns (uint256, uint256);

    function clearCachedSwap(uint16 _srcChainId, bytes calldata _srcAddress, uint256 _nonce) external;

    function factory() external view returns (address);

    function bridge() external view returns (address);

    function cachedSwapLookup(
        uint16 _chainId_,
        bytes calldata _srcAddress,
        uint256 _nonce
    ) external view returns (address token, uint256 amountLD, address to, bytes memory payload);
}

File 16 of 39 : ICrossChainDispatcher.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/@layerzerolabs/solidity-examples/contracts-upgradeable/token/oft/composable/IOFTReceiverUpgradeable.sol";
import "../dependencies/stargate-protocol/interfaces/IStargateReceiver.sol";
import "../dependencies/stargate-protocol/interfaces/IStargateRouter.sol";
import "../dependencies/stargate-protocol/interfaces/IStargateComposer.sol";
import "./IProxyOFT.sol";

interface ICrossChainDispatcher is IStargateReceiver, IOFTReceiverUpgradeable {
    function crossChainDispatcherOf(uint16 chainId_) external view returns (address);

    function triggerFlashRepaySwap(
        uint256 id_,
        address payable account_,
        address tokenIn_,
        address tokenOut_,
        uint256 amountIn_,
        uint256 amountOutMin_,
        bytes calldata lzArgs_
    ) external payable;

    function triggerLeverageSwap(
        uint256 id_,
        address payable account_,
        address tokenIn_,
        address tokenOut_,
        uint256 amountIn_,
        uint256 amountOutMin,
        bytes calldata lzArgs_
    ) external payable;

    function isBridgingActive() external view returns (bool);

    function flashRepayCallbackTxGasLimit() external view returns (uint64);

    function flashRepaySwapTxGasLimit() external view returns (uint64);

    function leverageCallbackTxGasLimit() external view returns (uint64);

    function leverageSwapTxGasLimit() external view returns (uint64);

    function lzBaseGasLimit() external view returns (uint256);

    function stargateComposer() external view returns (IStargateComposer);

    function stargateSlippage() external view returns (uint256);

    function stargatePoolIdOf(address token_) external view returns (uint256);
}

File 17 of 39 : IDebtToken.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/openzeppelin/token/ERC20/extensions/IERC20Metadata.sol";
import "./ISyntheticToken.sol";

interface IDebtToken is IERC20Metadata {
    function lastTimestampAccrued() external view returns (uint256);

    function isActive() external view returns (bool);

    function syntheticToken() external view returns (ISyntheticToken);

    function accrueInterest() external;

    function debtIndex() external returns (uint256 debtIndex_);

    function burn(address from_, uint256 amount_) external;

    function issue(uint256 amount_, address to_) external returns (uint256 _issued, uint256 _fee);

    function flashIssue(address to_, uint256 amount_) external returns (uint256 _issued, uint256 _fee);

    function mint(address to_, uint256 amount_) external;

    function repay(address onBehalfOf_, uint256 amount_) external returns (uint256 _repaid, uint256 _fee);

    function repayAll(address onBehalfOf_) external returns (uint256 _repaid, uint256 _fee);

    function quoteIssueIn(uint256 amountToIssue_) external view returns (uint256 _amount, uint256 _fee);

    function quoteIssueOut(uint256 amount_) external view returns (uint256 _amountToIssue, uint256 _fee);

    function quoteRepayIn(uint256 amountToRepay_) external view returns (uint256 _amount, uint256 _fee);

    function quoteRepayOut(uint256 amount_) external view returns (uint256 _amountToRepay, uint256 _fee);

    function updateMaxTotalSupply(uint256 newMaxTotalSupply_) external;

    function updateInterestRate(uint256 newInterestRate_) external;

    function maxTotalSupply() external view returns (uint256);

    function interestRate() external view returns (uint256);

    function interestRatePerSecond() external view returns (uint256);

    function toggleIsActive() external;
}

File 18 of 39 : IDepositToken.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/openzeppelin/token/ERC20/extensions/IERC20Metadata.sol";

interface IDepositToken is IERC20Metadata {
    function underlying() external view returns (IERC20);

    function collateralFactor() external view returns (uint256);

    function unlockedBalanceOf(address account_) external view returns (uint256);

    function lockedBalanceOf(address account_) external view returns (uint256);

    function flashWithdraw(address account_, uint256 amount_) external returns (uint256 _withdrawn, uint256 _fee);

    function deposit(uint256 amount_, address onBehalfOf_) external returns (uint256 _deposited, uint256 _fee);

    function quoteDepositIn(uint256 amountToDeposit_) external view returns (uint256 _amount, uint256 _fee);

    function quoteDepositOut(uint256 amount_) external view returns (uint256 _amountToDeposit, uint256 _fee);

    function quoteWithdrawIn(uint256 amountToWithdraw_) external view returns (uint256 _amount, uint256 _fee);

    function quoteWithdrawOut(uint256 amount_) external view returns (uint256 _amountToWithdraw, uint256 _fee);

    function withdraw(uint256 amount_, address to_) external returns (uint256 _withdrawn, uint256 _fee);

    function seize(address from_, address to_, uint256 amount_) external;

    function updateCollateralFactor(uint128 newCollateralFactor_) external;

    function isActive() external view returns (bool);

    function toggleIsActive() external;

    function maxTotalSupply() external view returns (uint256);

    function updateMaxTotalSupply(uint256 newMaxTotalSupply_) external;

    function withdrawFrom(address from_, uint256 amount_) external returns (uint256 _withdrawn, uint256 _fee);
}

File 19 of 39 : IFeeProvider.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

/**
 * @notice FeeProvider interface
 */
interface IFeeProvider {
    struct LiquidationFees {
        uint128 liquidatorIncentive;
        uint128 protocolFee;
    }

    function defaultSwapFee() external view returns (uint256);

    function depositFee() external view returns (uint256);

    function issueFee() external view returns (uint256);

    function liquidationFees() external view returns (uint128 liquidatorIncentive, uint128 protocolFee);

    function repayFee() external view returns (uint256);

    function swapFeeFor(address account_) external view returns (uint256);

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

File 20 of 39 : IGovernable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

/**
 * @notice Governable interface
 */
interface IGovernable {
    function governor() external view returns (address _governor);

    function transferGovernorship(address _proposedGovernor) external;
}

File 21 of 39 : IManageable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./IPool.sol";

/**
 * @notice Manageable interface
 */
interface IManageable {
    function pool() external view returns (IPool _pool);
}

File 22 of 39 : IPauseable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface IPauseable {
    function paused() external view returns (bool);

    function everythingStopped() external view returns (bool);
}

File 23 of 39 : IPool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./IDepositToken.sol";
import "./IDebtToken.sol";
import "./ITreasury.sol";
import "./IRewardsDistributor.sol";
import "./IPoolRegistry.sol";
import "./IFeeProvider.sol";
import "./ISmartFarmingManager.sol";
import "./external/ISwapper.sol";
import "../interfaces/IFeeProvider.sol";

/**
 * @notice Pool interface
 */
interface IPool is IPauseable, IGovernable {
    function debtFloorInUsd() external view returns (uint256);

    function feeCollector() external view returns (address);

    function feeProvider() external view returns (IFeeProvider);

    function maxLiquidable() external view returns (uint256);

    function doesSyntheticTokenExist(ISyntheticToken syntheticToken_) external view returns (bool);

    function doesDebtTokenExist(IDebtToken debtToken_) external view returns (bool);

    function doesDepositTokenExist(IDepositToken depositToken_) external view returns (bool);

    function depositTokenOf(IERC20 underlying_) external view returns (IDepositToken);

    function debtTokenOf(ISyntheticToken syntheticToken_) external view returns (IDebtToken);

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

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

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

    function debtOf(address account_) external view returns (uint256 _debtInUsd);

    function depositOf(address account_) external view returns (uint256 _depositInUsd, uint256 _issuableLimitInUsd);

    function debtPositionOf(
        address account_
    )
        external
        view
        returns (
            bool _isHealthy,
            uint256 _depositInUsd,
            uint256 _debtInUsd,
            uint256 _issuableLimitInUsd,
            uint256 _issuableInUsd
        );

    function liquidate(
        ISyntheticToken syntheticToken_,
        address account_,
        uint256 amountToRepay_,
        IDepositToken depositToken_
    ) external returns (uint256 _totalSeized, uint256 _toLiquidator, uint256 _fee);

    function quoteLiquidateIn(
        ISyntheticToken syntheticToken_,
        uint256 totalToSeized_,
        IDepositToken depositToken_
    ) external view returns (uint256 _amountToRepay, uint256 _toLiquidator, uint256 _fee);

    function quoteLiquidateMax(
        ISyntheticToken syntheticToken_,
        address account_,
        IDepositToken depositToken_
    ) external view returns (uint256 _maxAmountToRepay);

    function quoteLiquidateOut(
        ISyntheticToken syntheticToken_,
        uint256 amountToRepay_,
        IDepositToken depositToken_
    ) external view returns (uint256 _totalSeized, uint256 _toLiquidator, uint256 _fee);

    function quoteSwapIn(
        ISyntheticToken syntheticTokenIn_,
        ISyntheticToken syntheticTokenOut_,
        uint256 amountOut_
    ) external view returns (uint256 _amountIn, uint256 _fee);

    function quoteSwapOut(
        ISyntheticToken syntheticTokenIn_,
        ISyntheticToken syntheticTokenOut_,
        uint256 amountIn_
    ) external view returns (uint256 _amountOut, uint256 _fee);

    function swap(
        ISyntheticToken syntheticTokenIn_,
        ISyntheticToken syntheticTokenOut_,
        uint256 amountIn_
    ) external returns (uint256 _amountOut, uint256 _fee);

    function treasury() external view returns (ITreasury);

    function masterOracle() external view returns (IMasterOracle);

    function poolRegistry() external view returns (IPoolRegistry);

    function addToDepositTokensOfAccount(address account_) external;

    function removeFromDepositTokensOfAccount(address account_) external;

    function addToDebtTokensOfAccount(address account_) external;

    function removeFromDebtTokensOfAccount(address account_) external;

    function getDepositTokensOfAccount(address account_) external view returns (address[] memory);

    function getDebtTokensOfAccount(address account_) external view returns (address[] memory);

    function isSwapActive() external view returns (bool);

    function smartFarmingManager() external view returns (ISmartFarmingManager);
}

File 24 of 39 : IPoolRegistry.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./external/IMasterOracle.sol";
import "./IPauseable.sol";
import "./IGovernable.sol";
import "./ISyntheticToken.sol";
import "./external/ISwapper.sol";
import "./IQuoter.sol";
import "./ICrossChainDispatcher.sol";

interface IPoolRegistry is IPauseable, IGovernable {
    function feeCollector() external view returns (address);

    function isPoolRegistered(address pool_) external view returns (bool);

    function nativeTokenGateway() external view returns (address);

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

    function registerPool(address pool_) external;

    function unregisterPool(address pool_) external;

    function masterOracle() external view returns (IMasterOracle);

    function updateFeeCollector(address newFeeCollector_) external;

    function idOfPool(address pool_) external view returns (uint256);

    function nextPoolId() external view returns (uint256);

    function swapper() external view returns (ISwapper);

    function quoter() external view returns (IQuoter);

    function crossChainDispatcher() external view returns (ICrossChainDispatcher);

    function doesSyntheticTokenExist(ISyntheticToken syntheticToken_) external view returns (bool _exists);
}

File 25 of 39 : IProxyOFT.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/@layerzerolabs/solidity-examples/contracts-upgradeable/token/oft/composable/IComposableOFTCoreUpgradeable.sol";

interface IProxyOFT is IComposableOFTCoreUpgradeable {
    function getProxyOFTOf(uint16 chainId_) external view returns (address _proxyOFT);
}

File 26 of 39 : IQuoter.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./IPoolRegistry.sol";
import "./IProxyOFT.sol";

interface IQuoter {
    function quoteCrossChainFlashRepayNativeFee(
        IProxyOFT proxyOFT_,
        bytes calldata lzArgs_
    ) external view returns (uint256 _nativeFee);

    function quoteCrossChainLeverageNativeFee(
        IProxyOFT proxyOFT_,
        bytes calldata lzArgs_
    ) external view returns (uint256 _nativeFee);

    function quoteLeverageCallbackNativeFee(uint16 dstChainId_) external view returns (uint256 _callbackTxNativeFee);

    function quoteFlashRepayCallbackNativeFee(uint16 dstChainId_) external view returns (uint256 _callbackTxNativeFee);

    function getFlashRepaySwapAndCallbackLzArgs(
        uint16 srcChainId_,
        uint16 dstChainId_
    ) external view returns (bytes memory lzArgs_);

    function getLeverageSwapAndCallbackLzArgs(
        uint16 srcChainId_,
        uint16 dstChainId_
    ) external view returns (bytes memory lzArgs_);
}

File 27 of 39 : IRewardsDistributor.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/openzeppelin/token/ERC20/IERC20.sol";

/**
 * @notice Reward Distributor interface
 */
interface IRewardsDistributor {
    function rewardToken() external view returns (IERC20);

    function tokenSpeeds(IERC20 token_) external view returns (uint256);

    function tokensAccruedOf(address account_) external view returns (uint256);

    function updateBeforeMintOrBurn(IERC20 token_, address account_) external;

    function updateBeforeTransfer(IERC20 token_, address from_, address to_) external;

    function claimable(address account_) external view returns (uint256 _claimable);

    function claimable(address account_, IERC20 token_) external view returns (uint256 _claimable);

    function claimRewards(address account_) external;

    function claimRewards(address account_, IERC20[] memory tokens_) external;

    function claimRewards(address[] memory accounts_, IERC20[] memory tokens_) external;

    function updateTokenSpeed(IERC20 token_, uint256 newSpeed_) external;

    function updateTokenSpeeds(IERC20[] calldata tokens_, uint256[] calldata speeds_) external;

    function tokens(uint256) external view returns (IERC20);

    function tokenStates(IERC20) external view returns (uint224 index, uint32 timestamp);

    function accountIndexOf(IERC20, address) external view returns (uint256);
}

File 28 of 39 : ISmartFarmingManager.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./IManageable.sol";
import "./IDepositToken.sol";
import "./IDebtToken.sol";

/**
 * @notice SmartFarmingManager interface
 */
interface ISmartFarmingManager {
    function flashRepay(
        ISyntheticToken syntheticToken_,
        IDepositToken depositToken_,
        uint256 withdrawAmount_,
        uint256 repayAmountMin_
    ) external returns (uint256 _withdrawn, uint256 _repaid);

    function crossChainFlashRepay(
        ISyntheticToken syntheticToken_,
        IDepositToken depositToken_,
        uint256 withdrawAmount_,
        IERC20 bridgeToken_,
        uint256 bridgeTokenAmountMin_,
        uint256 swapAmountOutMin_,
        uint256 repayAmountMin_,
        bytes calldata lzArgs_
    ) external payable;

    function crossChainLeverage(
        IERC20 tokenIn_,
        IDepositToken depositToken_,
        ISyntheticToken syntheticToken_,
        uint256 amountIn_,
        uint256 leverage_,
        uint256 swapAmountOutMin_,
        uint256 depositAmountMin_,
        bytes calldata lzArgs_
    ) external payable;

    function crossChainLeverageCallback(uint256 id_, uint256 swapAmountOut_) external returns (uint256 _deposited);

    function crossChainFlashRepayCallback(uint256 id_, uint256 swapAmountOut_) external returns (uint256 _repaid);

    function leverage(
        IERC20 tokenIn_,
        IDepositToken depositToken_,
        ISyntheticToken syntheticToken_,
        uint256 amountIn_,
        uint256 leverage_,
        uint256 depositAmountMin_
    ) external returns (uint256 _deposited, uint256 _issued);
}

File 29 of 39 : ISyntheticToken.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/openzeppelin/token/ERC20/extensions/IERC20Metadata.sol";
import "./IDebtToken.sol";
import "./IPoolRegistry.sol";
import "../interfaces/IProxyOFT.sol";

interface ISyntheticToken is IERC20Metadata {
    function isActive() external view returns (bool);

    function mint(address to_, uint256 amount_) external;

    function burn(address from_, uint256 amount) external;

    function poolRegistry() external view returns (IPoolRegistry);

    function toggleIsActive() external;

    function seize(address from_, address to_, uint256 amount_) external;

    function updateMaxTotalSupply(uint256 newMaxTotalSupply_) external;

    function updateProxyOFT(IProxyOFT newProxyOFT_) external;

    function maxTotalSupply() external view returns (uint256);

    function proxyOFT() external view returns (IProxyOFT);
}

File 30 of 39 : ITreasury.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface ITreasury {
    function pull(address to_, uint256 amount_) external;

    function migrateTo(address newTreasury_) external;
}

File 31 of 39 : IMasterOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface IMasterOracle {
    function quoteTokenToUsd(address _asset, uint256 _amount) external view returns (uint256 _amountInUsd);

    function quoteUsdToToken(address _asset, uint256 _amountInUsd) external view returns (uint256 _amount);

    function quote(address _assetIn, address _assetOut, uint256 _amountIn) external view returns (uint256 _amountOut);
}

File 32 of 39 : IStargateComposerWithRetry.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.9;

import "../../dependencies/stargate-protocol/interfaces/IStargateComposer.sol";

// Note: Extending interface instead of adding those function to avoid triggering upgrade for other contracts
// We may move functions to `IStargateComposer` on the next major upgrade
interface IStargateComposerWithRetry is IStargateComposer {
    function payloadHashes(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        uint256 _nonce
    ) external view returns (bytes32);

    function clearCachedSwap(
        uint16 _srcChainId,
        bytes calldata _srcAddress,
        uint64 _nonce,
        address _receiver,
        bytes calldata _sgReceiveCallData
    ) external;
}

File 33 of 39 : IStargateFactory.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface IStargateFactory {
    function getPool(uint256 _id) external view returns (address _pool);
}

File 34 of 39 : IStargatePool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface IStargatePool {
    function token() external view returns (address _token);
}

File 35 of 39 : ISwapper.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface ISwapper {
    function swapExactInput(
        address tokenIn_,
        address tokenOut_,
        uint256 amountIn_,
        uint256 amountOutMin_,
        address receiver_
    ) external returns (uint256 _amountOut);
}

File 36 of 39 : IWETH.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../../dependencies/openzeppelin/token/ERC20/IERC20.sol";

interface IWETH is IERC20 {
    function deposit() external payable;

    function withdraw(uint256) external;
}

File 37 of 39 : CrossChainLib.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

library CrossChainLib {
    /**
     * @notice Supported cross-chain operations
     */
    uint8 public constant LEVERAGE = 1;
    uint8 public constant FLASH_REPAY = 2;

    function getOperationType(bytes memory payload_) internal pure returns (uint8 _op) {
        (_op, ) = abi.decode(payload_, (uint8, bytes));
    }

    function encodeLeverageCallbackPayload(
        address srcSmartFarmingManager_,
        uint256 requestId_
    ) internal pure returns (bytes memory _payload) {
        return abi.encode(LEVERAGE, abi.encode(srcSmartFarmingManager_, requestId_));
    }

    function decodeLeverageCallbackPayload(
        bytes memory payload_
    ) internal pure returns (address _srcSmartFarmingManager, uint256 _requestId) {
        (, payload_) = abi.decode(payload_, (uint8, bytes));
        return abi.decode(payload_, (address, uint256));
    }

    function encodeFlashRepayCallbackPayload(
        address srcProxyOFT_,
        address srcSmartFarmingManager_,
        uint256 requestId_
    ) internal pure returns (bytes memory _payload) {
        return abi.encode(FLASH_REPAY, abi.encode(srcProxyOFT_, srcSmartFarmingManager_, requestId_));
    }

    function decodeFlashRepayCallbackPayload(
        bytes memory payload_
    ) internal pure returns (address srcProxyOFT_, address _srcSmartFarmingManager, uint256 _requestId) {
        (, payload_) = abi.decode(payload_, (uint8, bytes));
        return abi.decode(payload_, (address, address, uint256));
    }

    function encodeFlashRepaySwapPayload(
        address srcSmartFarmingManager_,
        address dstProxyOFT_,
        uint256 requestId_,
        address account_,
        uint256 amountOutMin_
    ) internal pure returns (bytes memory _payload) {
        return
            abi.encode(
                FLASH_REPAY,
                abi.encode(srcSmartFarmingManager_, dstProxyOFT_, requestId_, account_, amountOutMin_)
            );
    }

    function decodeFlashRepaySwapPayload(
        bytes memory payload_
    )
        internal
        pure
        returns (
            address srcSmartFarmingManager_,
            address dstProxyOFT_,
            uint256 requestId_,
            address account_,
            uint256 amountOutMin_
        )
    {
        (, payload_) = abi.decode(payload_, (uint8, bytes));
        return abi.decode(payload_, (address, address, uint256, address, uint256));
    }

    function encodeLeverageSwapPayload(
        address srcSmartFarmingManager_,
        address dstProxyOFT_,
        uint256 requestId_,
        uint256 sgPoolId_,
        address account_,
        uint256 amountOutMin_
    ) internal pure returns (bytes memory _payload) {
        return
            abi.encode(
                LEVERAGE,
                abi.encode(srcSmartFarmingManager_, dstProxyOFT_, requestId_, sgPoolId_, account_, amountOutMin_)
            );
    }

    function decodeLeverageSwapPayload(
        bytes memory payload_
    )
        internal
        pure
        returns (
            address srcSmartFarmingManager_,
            address dstProxyOFT_,
            uint256 requestId_,
            uint256 sgPoolId_,
            address account_,
            uint256 amountOutMin_
        )
    {
        (, payload_) = abi.decode(payload_, (uint8, bytes));
        return abi.decode(payload_, (address, address, uint256, uint256, address, uint256));
    }

    function encodeLzArgs(
        uint16 dstChainId_,
        uint256 callbackNativeFee_,
        uint64 swapTxGasLimit_
    ) internal pure returns (bytes memory _lzArgs) {
        return abi.encode(dstChainId_, callbackNativeFee_, swapTxGasLimit_);
    }

    function decodeLzArgs(
        bytes memory lzArgs_
    ) internal pure returns (uint16 dstChainId_, uint256 callbackNativeFee_, uint64 swapTxGasLimit_) {
        return abi.decode(lzArgs_, (uint16, uint256, uint64));
    }
}

File 38 of 39 : CrossChainDispatcherStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../interfaces/ICrossChainDispatcher.sol";
import "../interfaces/IPoolRegistry.sol";

abstract contract CrossChainDispatcherStorageV1 is ICrossChainDispatcher {
    /**
     * @notice The pool registry contract
     */
    IPoolRegistry public poolRegistry;

    /**
     * @notice Overwritten swap slippage params
     * @dev Used by retry functions in case of swap failure due to slippage (See: `_swap()`)
     */
    mapping(uint256 => uint256) public swapAmountOutMin;

    /**
     * @notice Maps other chains `CrossChainDispatcher` contracts
     */
    mapping(uint16 => address) public crossChainDispatcherOf;

    /**
     * @notice The base gas to pay for cross-chain calls
     * @dev This limit covers basic token transfer LZ cost
     */
    uint256 public lzBaseGasLimit;

    /**
     * @notice The slippage we're willing to accept for SG like:like transfers
     */
    uint256 public stargateSlippage;

    /**
     * @notice The gas limit to cover `_crossChainFlashRepayCallback()` call
     */
    uint64 public flashRepayCallbackTxGasLimit;

    /**
     * @notice The gas limit to cover `_swapAndTriggerFlashRepayCallback()` call
     */
    uint64 public flashRepaySwapTxGasLimit;

    /**
     * @notice The gas limit to cover `_crossChainLeverageCallback()` call
     */
    uint64 public leverageCallbackTxGasLimit;

    /**
     * @notice The gas limit to cover `_swapAndTriggerLeverageCallback()` call
     */
    uint64 public leverageSwapTxGasLimit;

    /**
     * @notice Flag that pause/unpause all cross-chain activities
     */
    bool public isBridgingActive;

    /**
     * @notice The Stargate Router contract
     */
    IStargateComposer public stargateComposer;

    /**
     * @notice Maps Stargate's token pools
     */
    mapping(address => uint256) public stargatePoolIdOf;

    /**
     * @notice Maps supported cross-chain routes (i.e. which chains are allowed to be used as source of liquidity)
     */
    mapping(uint16 => bool) public isDestinationChainSupported;

    /**
     * @notice WETH contract
     */
    address public weth;

    /**
     * @notice SGETH contract
     */
    address public sgeth;
}

File 39 of 39 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;
import "../dependencies/openzeppelin-upgradeable/proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressIsNull","type":"error"},{"inputs":[],"name":"BridgingIsPaused","type":"error"},{"inputs":[],"name":"DestinationChainNotAllowed","type":"error"},{"inputs":[],"name":"InvalidCallData","type":"error"},{"inputs":[],"name":"InvalidFromAddress","type":"error"},{"inputs":[],"name":"InvalidMsgSender","type":"error"},{"inputs":[],"name":"InvalidOperationType","type":"error"},{"inputs":[],"name":"InvalidPayload","type":"error"},{"inputs":[],"name":"NewValueIsSameAsCurrent","type":"error"},{"inputs":[],"name":"SenderIsNotGovernor","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"newIsActive","type":"bool"}],"name":"BridgingIsActiveUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"chainId","type":"uint16"},{"indexed":false,"internalType":"address","name":"oldCrossChainDispatcher","type":"address"},{"indexed":false,"internalType":"address","name":"newCrossChainDispatcher","type":"address"}],"name":"CrossChainDispatcherUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"chainId","type":"uint16"},{"indexed":false,"internalType":"bool","name":"newIsSupported","type":"bool"}],"name":"DestinationChainIsSupportedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"oldCallbackTxGasLimit","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newCallbackTxGasLimit","type":"uint64"}],"name":"FlashRepayCallbackTxGasLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"oldSwapTxGasLimit","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newSwapTxGasLimit","type":"uint64"}],"name":"FlashRepaySwapTxGasLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"oldCallbackTxGasLimit","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newCallbackTxGasLimit","type":"uint64"}],"name":"LeverageCallbackTxGasLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"oldSwapTxGasLimit","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newSwapTxGasLimit","type":"uint64"}],"name":"LeverageSwapTxGasLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLzBaseGasLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLzBaseGasLimit","type":"uint256"}],"name":"LzBaseGasLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IStargateComposer","name":"oldStargateComposer","type":"address"},{"indexed":false,"internalType":"contract IStargateComposer","name":"newStargateComposer","type":"address"}],"name":"StargateComposerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldPoolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPoolId","type":"uint256"}],"name":"StargatePoolIdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldStargateSlippage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStargateSlippage","type":"uint256"}],"name":"StargateSlippageUpdated","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"crossChainDispatcherOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flashRepayCallbackTxGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flashRepaySwapTxGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IPoolRegistry","name":"poolRegistry_","type":"address"},{"internalType":"address","name":"weth_","type":"address"},{"internalType":"address","name":"sgeth_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBridgingActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"isDestinationChainSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leverageCallbackTxGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leverageSwapTxGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lzBaseGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"from_","type":"bytes"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"payload_","type":"bytes"}],"name":"onOFTReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolRegistry","outputs":[{"internalType":"contract IPoolRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"srcAddress_","type":"bytes"},{"internalType":"uint64","name":"nonce_","type":"uint64"},{"internalType":"address","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"payload_","type":"bytes"},{"internalType":"uint256","name":"newAmountOutMin_","type":"uint256"}],"name":"retrySwapAndTriggerFlashRepayCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"srcAddress_","type":"bytes"},{"internalType":"uint64","name":"nonce_","type":"uint64"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"payload_","type":"bytes"},{"internalType":"uint256","name":"newAmountOutMin_","type":"uint256"}],"name":"retrySwapAndTriggerLeverageCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"srcAddress_","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"token_","type":"address"},{"internalType":"uint256","name":"amountLD_","type":"uint256"},{"internalType":"bytes","name":"payload_","type":"bytes"}],"name":"sgReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sgeth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stargateComposer","outputs":[{"internalType":"contract IStargateComposer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stargatePoolIdOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stargateSlippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"swapAmountOutMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleBridgingIsActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"toggleDestinationChainIsActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId_","type":"uint256"},{"internalType":"address payable","name":"account_","type":"address"},{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"},{"internalType":"uint256","name":"amountIn_","type":"uint256"},{"internalType":"uint256","name":"amountOutMin_","type":"uint256"},{"internalType":"bytes","name":"lzArgs_","type":"bytes"}],"name":"triggerFlashRepaySwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId_","type":"uint256"},{"internalType":"address payable","name":"account_","type":"address"},{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"},{"internalType":"uint256","name":"amountIn_","type":"uint256"},{"internalType":"uint256","name":"amountOutMin_","type":"uint256"},{"internalType":"bytes","name":"lzArgs_","type":"bytes"}],"name":"triggerLeverageSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"address","name":"crossChainDispatcher_","type":"address"}],"name":"updateCrossChainDispatcherOf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newFlashRepayCallbackTxGasLimit_","type":"uint64"}],"name":"updateFlashRepayCallbackTxGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newFlashRepaySwapTxGasLimit_","type":"uint64"}],"name":"updateFlashRepaySwapTxGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newLeverageCallbackTxGasLimit_","type":"uint64"}],"name":"updateLeverageCallbackTxGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newLeverageSwapTxGasLimit_","type":"uint64"}],"name":"updateLeverageSwapTxGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLzBaseGasLimit_","type":"uint256"}],"name":"updateLzBaseGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStargateComposer","name":"newStargateComposer_","type":"address"}],"name":"updateStargateComposer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"},{"internalType":"uint256","name":"newPoolId_","type":"uint256"}],"name":"updateStargatePoolIdOf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newStargateSlippage_","type":"uint256"}],"name":"updateStargateSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b506200001c62000022565b62000152565b6200002e60ff62000031565b50565b60008054610100900460ff1615620000ca578160ff1660011480156200006a575062000068306200014360201b6200251d1760201c565b155b620000c25760405162461bcd60e51b815260206004820152602e602482015260008051602062004be383398151915260448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b506000919050565b60005460ff808416911610620001295760405162461bcd60e51b815260206004820152602e602482015260008051602062004be383398151915260448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401620000b9565b506000805460ff191660ff92909216919091179055600190565b6001600160a01b03163b151590565b614a8180620001626000396000f3fe6080604052600436106101fc5760003560e01c80638a9cadaf1161010d578063b71b42ec116100a0578063dfda255f1161006f578063dfda255f146105e4578063e3499aa41461061a578063e3d47ece1461064a578063e7f4c16b14610671578063ffa1ad741461069857600080fd5b8063b71b42ec14610557578063b9d8172014610577578063c0c53b8b14610597578063d89921cb146105b757600080fd5b8063ab8236f3116100dc578063ab8236f3146104d7578063ac18fce6146104f7578063afcff50f14610517578063b2d083c11461053757600080fd5b80638a9cadaf1461044a5780638ece68571461046a578063a761f5f01461048a578063ab4193e2146104aa57600080fd5b80633413f1c1116101905780636a46aa381161015f5780636a46aa38146103bf5780636c77d24f146103df5780636e406753146103f55780637b7305d314610415578063833667df1461043557600080fd5b80633413f1c11461034857806339f648bf1461036c5780633fc8cef31461037f57806362491b351461039f57600080fd5b80631e492d56116101cc5780631e492d56146102a15780632b80cc52146102c15780632e369cf2146102eb5780633352b6081461030b57600080fd5b8062bc9db9146102085780630b211f0f1461021d578063147a7d71146102615780631a607f9a1461028157600080fd5b3661020357005b600080fd5b61021b610216366004613d90565b6106d6565b005b34801561022957600080fd5b5060075461024490600160801b90046001600160401b031681565b6040516001600160401b0390911681526020015b60405180910390f35b34801561026d57600080fd5b5061021b61027c366004613e4c565b610b06565b34801561028d57600080fd5b5061021b61029c366004613f18565b610c64565b3480156102ad57600080fd5b5061021b6102bc366004613f31565b610d7e565b3480156102cd57600080fd5b506008546102db9060ff1681565b6040519015158152602001610258565b3480156102f757600080fd5b5061021b610306366004613f4e565b610ed9565b34801561031757600080fd5b506008546103309061010090046001600160a01b031681565b6040516001600160a01b039091168152602001610258565b34801561035457600080fd5b5061035e60065481565b604051908152602001610258565b61021b61037a366004613d90565b611032565b34801561038b57600080fd5b50600b54610330906001600160a01b031681565b3480156103ab57600080fd5b50600754610244906001600160401b031681565b3480156103cb57600080fd5b5061021b6103da366004613f18565b611446565b3480156103eb57600080fd5b5061035e60055481565b34801561040157600080fd5b5061021b610410366004613f31565b611560565b34801561042157600080fd5b5061021b610430366004613f6b565b6116c0565b34801561044157600080fd5b5061021b611812565b34801561045657600080fd5b5061021b610465366004613f97565b611919565b34801561047657600080fd5b5061021b610485366004614053565b611bbe565b34801561049657600080fd5b50600c54610330906001600160a01b031681565b3480156104b657600080fd5b5061035e6104c5366004613f18565b60036020526000908152604090205481565b3480156104e357600080fd5b5061021b6104f236600461414f565b611d39565b34801561050357600080fd5b5061021b610512366004613f31565b611ea3565b34801561052357600080fd5b50600254610330906001600160a01b031681565b34801561054357600080fd5b5061021b6105523660046141eb565b611ff2565b34801561056357600080fd5b5061021b610572366004613f31565b61211e565b34801561058357600080fd5b5061021b610592366004614208565b612283565b3480156105a357600080fd5b5061021b6105b23660046142af565b612416565b3480156105c357600080fd5b5061035e6105d2366004613f4e565b60096020526000908152604090205481565b3480156105f057600080fd5b506103306105ff3660046141eb565b6004602052600090815260409020546001600160a01b031681565b34801561062657600080fd5b506102db6106353660046141eb565b600a6020526000908152604090205460ff1681565b34801561065657600080fd5b5060075461024490600160c01b90046001600160401b031681565b34801561067d57600080fd5b5060075461024490600160401b90046001600160401b031681565b3480156106a457600080fd5b506106c9604051806040016040528060058152602001640312e332e360dc1b81525081565b6040516102589190614352565b600260015414156107025760405162461bcd60e51b81526004016106f990614365565b60405180910390fd5b60026001819055506000336001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561074557600080fd5b505afa158015610759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077d919061439c565b60025460405163c673bdaf60e01b81526001600160a01b03808416600483015292935091169063c673bdaf9060240160206040518083038186803b1580156107c457600080fd5b505afa1580156107d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fc91906143b9565b61081957604051633bfe162b60e01b815260040160405180910390fd5b806001600160a01b03166396aaccfe6040518163ffffffff1660e01b815260040160206040518083038186803b15801561085257600080fd5b505afa158015610866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088a919061439c565b6001600160a01b0316336001600160a01b0316146108bb57604051633bfe162b60e01b815260040160405180910390fd5b60085460ff166108de57604051635621fccf60e01b815260040160405180910390fd5b6000889050600080600061092787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061252c92505050565b925092509250606060008b6001600160a01b0316636d1bb8f76040518163ffffffff1660e01b815260040160206040518083038186803b15801561096a57600080fd5b505afa15801561097e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a2919061439c565b6040516001627dd58f60e11b0319815261ffff871660048201526001600160a01b03919091169063ff0454e29060240160206040518083038186803b1580156109ea57600080fd5b505afa1580156109fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a22919061439c565b90506001600160a01b038116610a4b5760405163fb7566d760e01b815260040160405180910390fd5b61ffff85166000908152600a602052604090205460ff16610a7f5760405163334dc1fd60e01b815260040160405180910390fd5b8e610a8d3383838a8f612552565b92505050610af26040518061010001604052808e6001600160a01b031681526020018661ffff1681526020018c8152602001348152602001838152602001876001600160a01b03168152602001846001600160401b03168152602001858152506125c1565b505060018055505050505050505050505050565b610b0f33612870565b610b2c57604051633bfe162b60e01b815260040160405180910390fd5b6000610b72600087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050612a0b9050565b90506001600160a01b0381161580610ba9575061ffff8a166000908152600460205260409020546001600160a01b03828116911614155b15610bc757604051637ab628f960e01b815260040160405180910390fd5b6000610c0884848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a7092505050565b905060ff811660021415610c2657610c21858585612a8d565b610c57565b60ff811660011415610c3e57610c218b868686612bf6565b604051630ead561960e11b815260040160405180910390fd5b5050505050505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610cb257600080fd5b505afa158015610cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cea919061439c565b6001600160a01b0316336001600160a01b031614610d1b57604051634b98449160e11b815260040160405180910390fd5b60065481811415610d3f57604051630333a68160e41b815260040160405180910390fd5b60408051828152602081018490527f5cac1093ddd8c1e9cbcd89b2f36fa1889e966cc257753af2d160888564fd9818910160405180910390a150600655565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610dcc57600080fd5b505afa158015610de0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e04919061439c565b6001600160a01b0316336001600160a01b031614610e3557604051634b98449160e11b815260040160405180910390fd5b6007546001600160401b03600160c01b9091048116908216811415610e6d57604051630333a68160e41b815260040160405180910390fd5b604080516001600160401b038084168252841660208201527f7dd9d7c71da5859a7d6e34c00f4889cb529dbbc009a358db124855baa125a4dc910160405180910390a150600780546001600160401b03909216600160c01b026001600160c01b03909216919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610f2757600080fd5b505afa158015610f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5f919061439c565b6001600160a01b0316336001600160a01b031614610f9057604051634b98449160e11b815260040160405180910390fd5b6008546001600160a01b036101009091048116908216811415610fc657604051630333a68160e41b815260040160405180910390fd5b604080516001600160a01b038084168252841660208201527f398baf83f237e7e1e1ce6637c69193c52e8b6382036ceb3c6eba08401e327667910160405180910390a150600880546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600260015414156110555760405162461bcd60e51b81526004016106f990614365565b60026001819055506000336001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561109857600080fd5b505afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d0919061439c565b60025460405163c673bdaf60e01b81526001600160a01b03808416600483015292935091169063c673bdaf9060240160206040518083038186803b15801561111757600080fd5b505afa15801561112b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114f91906143b9565b61116c57604051633bfe162b60e01b815260040160405180910390fd5b806001600160a01b03166396aaccfe6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111a557600080fd5b505afa1580156111b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111dd919061439c565b6001600160a01b0316336001600160a01b03161461120e57604051633bfe162b60e01b815260040160405180910390fd5b6000889050600080600061125787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061252c92505050565b925092509250606060008c6001600160a01b0316636d1bb8f76040518163ffffffff1660e01b815260040160206040518083038186803b15801561129a57600080fd5b505afa1580156112ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d2919061439c565b6040516001627dd58f60e11b0319815261ffff871660048201526001600160a01b03919091169063ff0454e29060240160206040518083038186803b15801561131a57600080fd5b505afa15801561132e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611352919061439c565b90506001600160a01b03811661137b5760405163fb7566d760e01b815260040160405180910390fd5b61ffff85166000908152600a602052604090205460ff166113af5760405163334dc1fd60e01b815260040160405180910390fd5b6001600160a01b038c166000908152600960205260409020548f908d908c906113df903390869086908d86612fe0565b945050505050610af26040518061010001604052808e6001600160a01b031681526020018661ffff1681526020018c8152602001348152602001838152602001876001600160a01b03168152602001846001600160401b0316815260200185815250613058565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561149457600080fd5b505afa1580156114a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cc919061439c565b6001600160a01b0316336001600160a01b0316146114fd57604051634b98449160e11b815260040160405180910390fd5b6005548181141561152157604051630333a68160e41b815260040160405180910390fd5b60408051828152602081018490527f83c9ee8eed7101992146d1c75610cc54c1db740210cde12e135fa657a7850854910160405180910390a150600555565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b1580156115ae57600080fd5b505afa1580156115c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e6919061439c565b6001600160a01b0316336001600160a01b03161461161757604051634b98449160e11b815260040160405180910390fd5b6007546001600160401b03600160801b909104811690821681141561164f57604051630333a68160e41b815260040160405180910390fd5b604080516001600160401b038084168252841660208201527fce0317145f704f138aad728eeb9d95c91260950871930acca6e659f1b0883364910160405180910390a150600780546001600160401b03909216600160801b0267ffffffffffffffff60801b19909216919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561170e57600080fd5b505afa158015611722573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611746919061439c565b6001600160a01b0316336001600160a01b03161461177757604051634b98449160e11b815260040160405180910390fd5b6001600160a01b038216600090815260096020526040902054818114156117b157604051630333a68160e41b815260040160405180910390fd5b60408051828152602081018490526001600160a01b038516917ffa622ae921e227a42afec644139331c019f4157c54e93c82dd5f811ba210ac15910160405180910390a2506001600160a01b03909116600090815260096020526040902055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561186057600080fd5b505afa158015611874573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611898919061439c565b6001600160a01b0316336001600160a01b0316146118c957604051634b98449160e11b815260040160405180910390fd5b60085460405160ff90911615808252907f0269774d3426d7e61b04b7d5129948b9f4edf9b937bb0c657fbb32a94a7996ec9060200160405180910390a16008805460ff1916911515919091179055565b6002600154141561193c5760405162461bcd60e51b81526004016106f990614365565b600260015560085461ffff8a1660009081526004602090815260408083205490516001600160a01b0361010090950485169463ab8236f360e01b938f9361198693921691016143db565b60408051601f19818403018152908290526119ae92918c908c908c908c908c90602401614421565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b031990951694909417909352519092506000916119f6913091859101614484565b60408051601f198184030181529082905280516020909101206302902aeb60e41b825291506001600160a01b03841690632902aeb090611a40908f908f908f908f906004016144bc565b60206040518083038186803b158015611a5857600080fd5b505afa158015611a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9091906144f4565b8114611aaf57604051631c49f4d160e01b815260040160405180910390fd5b600080611af188888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061323892505050565b50935093505050806001600160a01b0316336001600160a01b031614611b2a57604051633bfe162b60e01b815260040160405180910390fd5b856003600084815260200190815260200160002081905550846001600160a01b031663c0e6ac6c8f8f8f8f308a6040518763ffffffff1660e01b8152600401611b789695949392919061450d565b600060405180830381600087803b158015611b9257600080fd5b505af1158015611ba6573d6000803e3d6000fd5b50506001805550505050505050505050505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015611c0c57600080fd5b505afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c44919061439c565b6001600160a01b0316336001600160a01b031614611c7557604051634b98449160e11b815260040160405180910390fd5b61ffff82166000908152600460205260409020546001600160a01b03908116908216811415611cb757604051630333a68160e41b815260040160405180910390fd5b6040805161ffff851681526001600160a01b03838116602083015284168183015290517fa0670378b7d4511893529175129417ed82867197a3ea18eb2743483bd4f00c2a9181900360600190a15061ffff91909116600090815260046020526040902080546001600160a01b0319166001600160a01b03909216919091179055565b60085461010090046001600160a01b03163314611d6957604051633bfe162b60e01b815260040160405180910390fd5b600c546001600160a01b0384811691161415611df757600b60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015611dcf57600080fd5b505af1158015611de3573d6000803e3d6000fd5b5050600b546001600160a01b031695505050505b6000611e038682612a0b565b90506001600160a01b0381161580611e3a575061ffff87166000908152600460205260409020546001600160a01b03828116911614155b15611e5857604051637ab628f960e01b815260040160405180910390fd5b6000611e6383612a70565b905060ff811660011415611e8157611e7c85858561327f565b611e99565b60ff811660021415610c3e57611e7c88868686613342565b5050505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ef157600080fd5b505afa158015611f05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f29919061439c565b6001600160a01b0316336001600160a01b031614611f5a57604051634b98449160e11b815260040160405180910390fd5b6007546001600160401b03908116908216811415611f8b57604051630333a68160e41b815260040160405180910390fd5b604080516001600160401b038084168252841660208201527f1701885e1db4da3ff923033aa465855dde857275866d4f132af5384aa880554f910160405180910390a1506007805467ffffffffffffffff19166001600160401b0392909216919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561204057600080fd5b505afa158015612054573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612078919061439c565b6001600160a01b0316336001600160a01b0316146120a957604051634b98449160e11b815260040160405180910390fd5b61ffff81166000908152600a602090815260409182902054915160ff90921615808352917f0269774d3426d7e61b04b7d5129948b9f4edf9b937bb0c657fbb32a94a7996ec910160405180910390a161ffff919091166000908152600a60205260409020805460ff1916911515919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561216c57600080fd5b505afa158015612180573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121a4919061439c565b6001600160a01b0316336001600160a01b0316146121d557604051634b98449160e11b815260040160405180910390fd5b6007546001600160401b03600160401b909104811690821681141561220d57604051630333a68160e41b815260040160405180910390fd5b604080516001600160401b038084168252841660208201527f8dbd2ecaaca80db9e2e655edc0f1b4df2c87f441eaedf46e0b7b00358d97ad30910160405180910390a150600780546001600160401b03909216600160401b026fffffffffffffffff000000000000000019909216919091179055565b600260015414156122a65760405162461bcd60e51b81526004016106f990614365565b600260018190555060008060006122f286868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506135d792505050565b50945050935093505061230483612870565b61232157604051637c6953f960e01b815260040160405180910390fd5b336001600160a01b0382161461234a57604051633bfe162b60e01b815260040160405180910390fd5b600082815260036020908152604080832087905561ffff8e16835260048252808320549051612385926001600160a01b0390921691016143db565b6040516020818303038152906040529050836001600160a01b031663cfd6528e8d8d8d8d86308f8f8f6040518a63ffffffff1660e01b81526004016123d299989796959493929190614568565b600060405180830381600087803b1580156123ec57600080fd5b505af1158015612400573d6000803e3d6000fd5b5050600180555050505050505050505050505050565b60006124226001613621565b9050801561243a576000805461ff0019166101001790555b6001600160a01b0384166124615760405163fb7566d760e01b815260040160405180910390fd5b6124696136a9565b600280546001600160a01b038087166001600160a01b031992831617909255603260065562030d406005557a0b71b000000000000b71b0000000000007a12000000000000b71b0600755600b8054868416908316179055600c8054928516929091169190911790558015612517576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b6001600160a01b03163b151590565b60008060008380602001905181019061254591906145e2565b9250925092509193909250565b604080516001600160a01b038781166020830152868116828401526060808301879052908516608083015260a08083018590528351808403909101815260c08301909352916125a7916002919060e00161461a565b604051602081830303815290604052905095945050505050565b6125e560405180606001604052806000815260200160008152602001606081525090565b60208083015161ffff1660009081526004825260408082205490519192612618926001600160a01b0390921691016143db565b60408051601f19818403018152919052905060006126368282612a0b565b6001600160a01b0316141561265e5760405163fb7566d760e01b815260040160405180910390fd5b60405180606001604052808460c001516001600160401b031681526020018460e00151815260200160008560e00151116126b2576040805160006020820152016040516020818303038152906040526126b4565b825b905283516001600160a01b031660009081526009602052604081205460065492945091612710906126e5908261464c565b86604001516126f49190614663565b6126fe9190614682565b6080860151600854600b54885193945091926001600160a01b03610100909204821692908216911614156127b357600b546040808901519051632e1a7d4d60e01b81526001600160a01b0390921691632e1a7d4d916127639160040190815260200190565b600060405180830381600087803b15801561277d57600080fd5b505af1158015612791573d6000803e3d6000fd5b505050508660400151876060018181516127ab91906146a4565b9052506127e8565b86516127ca906001600160a01b03168260006136da565b604087015187516127e8916001600160a01b039091169083906136da565b806001600160a01b0316639fbf10fc8860600151896020015187888c60a001518d604001518a8e8e8c6040518b63ffffffff1660e01b8152600401612835999897969594939291906146bc565b6000604051808303818588803b15801561284e57600080fd5b505af1158015612862573d6000803e3d6000fd5b505050505050505050505050565b600080826001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128ac57600080fd5b505afa1580156128c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e4919061439c565b600254604051631a0dd00b60e01b81526001600160a01b038084166004830152929350911690631a0dd00b9060240160206040518083038186803b15801561292b57600080fd5b505afa15801561293f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296391906143b9565b6129705750600092915050565b806001600160a01b0316636d1bb8f76040518163ffffffff1660e01b815260040160206040518083038186803b1580156129a957600080fd5b505afa1580156129bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e1919061439c565b6001600160a01b0316836001600160a01b031614612a025750600092915050565b50600192915050565b6000612a188260146146a4565b83511015612a605760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b60448201526064016106f9565b500160200151600160601b900490565b600081806020019051810190612a86919061474a565b5092915050565b6000806000612ad185858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061382592505050565b9250925092506000836001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b1257600080fd5b505afa158015612b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4a919061439c565b9050612b616001600160a01b0382168460006136da565b612b756001600160a01b03821684896136da565b604051636455bf6f60e01b815260048101839052602481018890526001600160a01b03841690636455bf6f90604401602060405180830381600087803b158015612bbe57600080fd5b505af1158015612bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9991906144f4565b600080600080600080612c3e88888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506135d792505050565b9550955095509550955095506000600860019054906101000a90046001600160a01b03166001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9a57600080fd5b505afa158015612cae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd2919061439c565b6001600160a01b031663068bcd8d856040518263ffffffff1660e01b8152600401612cff91815260200190565b60206040518083038186803b158015612d1757600080fd5b505afa158015612d2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4f919061439c565b6001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8757600080fd5b505afa158015612d9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbf919061439c565b600c549091506001600160a01b0380831691161415612de65750600b546001600160a01b03165b612e6385876001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612e2357600080fd5b505afa158015612e37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5b919061439c565b838d86613857565b995060008b9050612862604051806101000160405280846001600160a01b031681526020018361ffff1681526020018d8152602001600260009054906101000a90046001600160a01b03166001600160a01b031663c6bbd5a76040518163ffffffff1660e01b815260040160206040518083038186803b158015612ee657600080fd5b505afa158015612efa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f1e919061439c565b60405163d81e47d360e01b815261ffff861660048201526001600160a01b03919091169063d81e47d39060240160206040518083038186803b158015612f6357600080fd5b505afa158015612f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9b91906144f4565b8152602001612faa8b8a6139ca565b81526001600160a01b0387166020820152600754600160801b90046001600160401b0316604082015260006060909101526125c1565b604080516001600160a01b0388811660208301528781168284015260608083018890526080830187905290851660a083015260c08083018590528351808403909101815260e083019093529161303d91600191906101000161461a565b60405160208183030381529060405290509695505050505050565b60208082015161ffff166000908152600490915260409020546001600160a01b0316806130985760405163fb7566d760e01b815260040160405180910390fd5b600060028360c001516001600160401b03166005546130b791906146a4565b60e0850151806130c85760006130ca565b845b604051602001613114949392919060f09490941b6001600160f01b03191684526002840192909252602283015260601b6bffffffffffffffffffffffff1916604282015260560190565b604051602081830303815290604052905082600001516001600160a01b0316636d1bb8f76040518163ffffffff1660e01b815260040160206040518083038186803b15801561316257600080fd5b505afa158015613176573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319a919061439c565b6001600160a01b031663e7f0c59f8460600151308660200151866040516020016131c491906143db565b60408051601f19818403018152828252908a015160808b015160c08c015160a08d01516001600160e01b031960e08b901b16865261320b9796956000908d906004016147dc565b6000604051808303818588803b15801561322457600080fd5b505af1158015611e99573d6000803e3d6000fd5b600080600080600085806020019051810190613254919061474a565b805190975061326d91508701602090810190880161485a565b939a9299509097509550909350915050565b60008061328b83613a1b565b90925090506132a56001600160a01b0386168360006136da565b6132b96001600160a01b03861683866136da565b6040516320159ddd60e21b815260048101829052602481018590526001600160a01b03831690638056777490604401602060405180830381600087803b15801561330257600080fd5b505af1158015613316573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061333a91906144f4565b505050505050565b600080600080600061335386613238565b945094509450945094506000846001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561339857600080fd5b505afa1580156133ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d0919061439c565b90506133df848a838b86613857565b6040516001627dd58f60e11b0319815261ffff8c1660048201529098508a906000906001600160a01b0388169063ff0454e29060240160206040518083038186803b15801561342d57600080fd5b505afa158015613441573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613465919061439c565b9050612862604051806101000160405280856001600160a01b031681526020018461ffff1681526020018c8152602001600260009054906101000a90046001600160a01b03166001600160a01b031663c6bbd5a76040518163ffffffff1660e01b815260040160206040518083038186803b1580156134e357600080fd5b505afa1580156134f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351b919061439c565b60405163665471cd60e11b815261ffff871660048201526001600160a01b03919091169063cca8e39a9060240160206040518083038186803b15801561356057600080fd5b505afa158015613574573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359891906144f4565b81526020016135a8848c8b613a54565b81526001600160a01b03881660208201526007546001600160401b031660408201526000606090910152613058565b600080600080600080868060200190518101906135f4919061474a565b805190985061360d9150880160209081019089016148bb565b949c939b5091995097509550909350915050565b60008054610100900460ff1615613668578160ff1660011480156136445750303b155b6136605760405162461bcd60e51b81526004016106f990614925565b506000919050565b60005460ff80841691161061368f5760405162461bcd60e51b81526004016106f990614925565b506000805460ff191660ff92909216919091179055600190565b600054610100900460ff166136d05760405162461bcd60e51b81526004016106f990614973565b6136d8613ab0565b565b8015806137635750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561372957600080fd5b505afa15801561373d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376191906144f4565b155b6137ce5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016106f9565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613820908490613add565b505050565b60008060008380602001905181019061383e919061474a565b80519095506125459150850160209081019086016149be565b600085815260036020526040812054801561387f576000878152600360205260408120559150815b60025460408051632b3297f960e01b815290516000926001600160a01b031691632b3297f9916004808301926020929190829003018186803b1580156138c457600080fd5b505afa1580156138d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138fc919061439c565b90506139136001600160a01b0388168260006136da565b6139276001600160a01b03881682876136da565b604051636ccb2b0160e01b81526001600160a01b03888116600483015287811660248301526044820187905260648201869052306084830152821690636ccb2b019060a401602060405180830381600087803b15801561398657600080fd5b505af115801561399a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139be91906144f4565b98975050505050505050565b604080516001600160a01b03841660208201528082018390528151808203830181526060808301909352613a04916001919060800161461a565b604051602081830303815290604052905092915050565b60008082806020019051810190613a32919061474a565b8051909450613a4b915084016020908101908501614a01565b91509150915091565b604080516001600160a01b03858116602083015284168183015260608082018490528251808303820181526080830190935291613a97916002919060a00161461a565b60405160208183030381529060405290505b9392505050565b600054610100900460ff16613ad75760405162461bcd60e51b81526004016106f990614973565b60018055565b6000613b32826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613baf9092919063ffffffff16565b8051909150156138205780806020019051810190613b5091906143b9565b6138205760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106f9565b6060613bbe8484600085613bc6565b949350505050565b606082471015613c275760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106f9565b6001600160a01b0385163b613c7e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106f9565b600080866001600160a01b03168587604051613c9a9190614a2f565b60006040518083038185875af1925050503d8060008114613cd7576040519150601f19603f3d011682016040523d82523d6000602084013e613cdc565b606091505b5091509150613cec828286613cf7565b979650505050505050565b60608315613d06575081613aa9565b825115613d165782518084602001fd5b8160405162461bcd60e51b81526004016106f99190614352565b6001600160a01b0381168114613d4557600080fd5b50565b60008083601f840112613d5a57600080fd5b5081356001600160401b03811115613d7157600080fd5b602083019150836020828501011115613d8957600080fd5b9250929050565b60008060008060008060008060e0898b031215613dac57600080fd5b883597506020890135613dbe81613d30565b96506040890135613dce81613d30565b95506060890135613dde81613d30565b94506080890135935060a0890135925060c08901356001600160401b03811115613e0757600080fd5b613e138b828c01613d48565b999c989b5096995094979396929594505050565b61ffff81168114613d4557600080fd5b6001600160401b0381168114613d4557600080fd5b600080600080600080600080600060c08a8c031215613e6a57600080fd5b8935613e7581613e27565b985060208a01356001600160401b0380821115613e9157600080fd5b613e9d8d838e01613d48565b909a50985060408c01359150613eb282613e37565b90965060608b01359080821115613ec857600080fd5b613ed48d838e01613d48565b909750955060808c0135945060a08c0135915080821115613ef457600080fd5b50613f018c828d01613d48565b915080935050809150509295985092959850929598565b600060208284031215613f2a57600080fd5b5035919050565b600060208284031215613f4357600080fd5b8135613aa981613e37565b600060208284031215613f6057600080fd5b8135613aa981613d30565b60008060408385031215613f7e57600080fd5b8235613f8981613d30565b946020939093013593505050565b600080600080600080600080600060e08a8c031215613fb557600080fd5b8935613fc081613e27565b985060208a01356001600160401b0380821115613fdc57600080fd5b613fe88d838e01613d48565b909a50985060408c01359150613ffd82613e37565b90965060608b01359061400f82613d30565b90955060808b0135945060a08b0135908082111561402c57600080fd5b506140398c828d01613d48565b9a9d999c50979a9699959894979660c00135949350505050565b6000806040838503121561406657600080fd5b823561407181613e27565b9150602083013561408181613d30565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156140ca576140ca61408c565b604052919050565b60006001600160401b038211156140eb576140eb61408c565b50601f01601f191660200190565b600082601f83011261410a57600080fd5b813561411d614118826140d2565b6140a2565b81815284602083860101111561413257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561416857600080fd5b863561417381613e27565b955060208701356001600160401b038082111561418f57600080fd5b61419b8a838b016140f9565b965060408901359550606089013591506141b482613d30565b9093506080880135925060a088013590808211156141d157600080fd5b506141de89828a016140f9565b9150509295509295509295565b6000602082840312156141fd57600080fd5b8135613aa981613e27565b60008060008060008060008060c0898b03121561422457600080fd5b883561422f81613e27565b975060208901356001600160401b038082111561424b57600080fd5b6142578c838d01613d48565b909950975060408b0135915061426c82613e37565b90955060608a0135945060808a0135908082111561428957600080fd5b506142968b828c01613d48565b999c989b50969995989497949560a00135949350505050565b6000806000606084860312156142c457600080fd5b83356142cf81613d30565b925060208401356142df81613d30565b915060408401356142ef81613d30565b809150509250925092565b60005b838110156143155781810151838201526020016142fd565b838111156125175750506000910152565b6000815180845261433e8160208601602086016142fa565b601f01601f19169290920160200192915050565b602081526000613aa96020830184614326565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6000602082840312156143ae57600080fd5b8151613aa981613d30565b6000602082840312156143cb57600080fd5b81518015158114613aa957600080fd5b60609190911b6bffffffffffffffffffffffff1916815260140190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61ffff8816815260c06020820152600061443e60c0830189614326565b6001600160401b03881660408401526001600160a01b03871660608401526080830186905282810360a08401526144768185876143f8565b9a9950505050505050505050565b6bffffffffffffffffffffffff198360601b168152600082516144ae8160148501602087016142fa565b919091016014019392505050565b61ffff851681526060602082015260006144da6060830185876143f8565b90506001600160401b038316604083015295945050505050565b60006020828403121561450657600080fd5b5051919050565b61ffff8716815260a06020820152600061452b60a0830187896143f8565b6001600160401b03861660408401526001600160a01b0385166060840152828103608084015261455b8185614326565b9998505050505050505050565b61ffff8a16815260e06020820152600061458660e083018a8c6143f8565b6001600160401b038916604084015282810360608401526145a78189614326565b6001600160a01b038816608085015260a0840187905283810360c085015290506145d28185876143f8565b9c9b505050505050505050505050565b6000806000606084860312156145f757600080fd5b835161460281613e27565b6020850151604086015191945092506142ef81613e37565b60ff83168152604060208201526000613bbe6040830184614326565b634e487b7160e01b600052601160045260246000fd5b60008282101561465e5761465e614636565b500390565b600081600019048311821515161561467d5761467d614636565b500290565b60008261469f57634e487b7160e01b600052601260045260246000fd5b500490565b600082198211156146b7576146b7614636565b500190565b600061012061ffff8c1683528a602084015289604084015260018060a01b03891660608401528760808401528660a08401528060c084015285518184015250602085015161014083015260408501516060610160840152614721610180840182614326565b905082810360e08401526147358186614326565b90508281036101008401526145d28185614326565b6000806040838503121561475d57600080fd5b825160ff8116811461476e57600080fd5b60208401519092506001600160401b0381111561478a57600080fd5b8301601f8101851361479b57600080fd5b80516147a9614118826140d2565b8181528660208385010111156147be57600080fd5b6147cf8260208301602086016142fa565b8093505050509250929050565b6001600160a01b038a8116825261ffff8a1660208301526101206040830181905260009161480c8483018c614326565b91508960608501528382036080850152614826828a614326565b6001600160401b03891660a086015287821660c086015290861660e085015283810361010085015290506145d28185614326565b600080600080600060a0868803121561487257600080fd5b855161487d81613d30565b602087015190955061488e81613d30565b6040870151606088015191955093506148a681613d30565b80925050608086015190509295509295909350565b60008060008060008060c087890312156148d457600080fd5b86516148df81613d30565b60208801519096506148f081613d30565b809550506040870151935060608701519250608087015161491081613d30565b8092505060a087015190509295509295509295565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000806000606084860312156149d357600080fd5b83516149de81613d30565b60208501519093506149ef81613d30565b80925050604084015190509250925092565b60008060408385031215614a1457600080fd5b8251614a1f81613d30565b6020939093015192949293505050565b60008251614a418184602087016142fa565b919091019291505056fea26469706673582212205c2b013588d662f1788335f277c81bde3395dfcb769803875155cb83f22cf5e364736f6c63430008090033496e697469616c697a61626c653a20636f6e747261637420697320616c726561

Deployed Bytecode

0x6080604052600436106101fc5760003560e01c80638a9cadaf1161010d578063b71b42ec116100a0578063dfda255f1161006f578063dfda255f146105e4578063e3499aa41461061a578063e3d47ece1461064a578063e7f4c16b14610671578063ffa1ad741461069857600080fd5b8063b71b42ec14610557578063b9d8172014610577578063c0c53b8b14610597578063d89921cb146105b757600080fd5b8063ab8236f3116100dc578063ab8236f3146104d7578063ac18fce6146104f7578063afcff50f14610517578063b2d083c11461053757600080fd5b80638a9cadaf1461044a5780638ece68571461046a578063a761f5f01461048a578063ab4193e2146104aa57600080fd5b80633413f1c1116101905780636a46aa381161015f5780636a46aa38146103bf5780636c77d24f146103df5780636e406753146103f55780637b7305d314610415578063833667df1461043557600080fd5b80633413f1c11461034857806339f648bf1461036c5780633fc8cef31461037f57806362491b351461039f57600080fd5b80631e492d56116101cc5780631e492d56146102a15780632b80cc52146102c15780632e369cf2146102eb5780633352b6081461030b57600080fd5b8062bc9db9146102085780630b211f0f1461021d578063147a7d71146102615780631a607f9a1461028157600080fd5b3661020357005b600080fd5b61021b610216366004613d90565b6106d6565b005b34801561022957600080fd5b5060075461024490600160801b90046001600160401b031681565b6040516001600160401b0390911681526020015b60405180910390f35b34801561026d57600080fd5b5061021b61027c366004613e4c565b610b06565b34801561028d57600080fd5b5061021b61029c366004613f18565b610c64565b3480156102ad57600080fd5b5061021b6102bc366004613f31565b610d7e565b3480156102cd57600080fd5b506008546102db9060ff1681565b6040519015158152602001610258565b3480156102f757600080fd5b5061021b610306366004613f4e565b610ed9565b34801561031757600080fd5b506008546103309061010090046001600160a01b031681565b6040516001600160a01b039091168152602001610258565b34801561035457600080fd5b5061035e60065481565b604051908152602001610258565b61021b61037a366004613d90565b611032565b34801561038b57600080fd5b50600b54610330906001600160a01b031681565b3480156103ab57600080fd5b50600754610244906001600160401b031681565b3480156103cb57600080fd5b5061021b6103da366004613f18565b611446565b3480156103eb57600080fd5b5061035e60055481565b34801561040157600080fd5b5061021b610410366004613f31565b611560565b34801561042157600080fd5b5061021b610430366004613f6b565b6116c0565b34801561044157600080fd5b5061021b611812565b34801561045657600080fd5b5061021b610465366004613f97565b611919565b34801561047657600080fd5b5061021b610485366004614053565b611bbe565b34801561049657600080fd5b50600c54610330906001600160a01b031681565b3480156104b657600080fd5b5061035e6104c5366004613f18565b60036020526000908152604090205481565b3480156104e357600080fd5b5061021b6104f236600461414f565b611d39565b34801561050357600080fd5b5061021b610512366004613f31565b611ea3565b34801561052357600080fd5b50600254610330906001600160a01b031681565b34801561054357600080fd5b5061021b6105523660046141eb565b611ff2565b34801561056357600080fd5b5061021b610572366004613f31565b61211e565b34801561058357600080fd5b5061021b610592366004614208565b612283565b3480156105a357600080fd5b5061021b6105b23660046142af565b612416565b3480156105c357600080fd5b5061035e6105d2366004613f4e565b60096020526000908152604090205481565b3480156105f057600080fd5b506103306105ff3660046141eb565b6004602052600090815260409020546001600160a01b031681565b34801561062657600080fd5b506102db6106353660046141eb565b600a6020526000908152604090205460ff1681565b34801561065657600080fd5b5060075461024490600160c01b90046001600160401b031681565b34801561067d57600080fd5b5060075461024490600160401b90046001600160401b031681565b3480156106a457600080fd5b506106c9604051806040016040528060058152602001640312e332e360dc1b81525081565b6040516102589190614352565b600260015414156107025760405162461bcd60e51b81526004016106f990614365565b60405180910390fd5b60026001819055506000336001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561074557600080fd5b505afa158015610759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077d919061439c565b60025460405163c673bdaf60e01b81526001600160a01b03808416600483015292935091169063c673bdaf9060240160206040518083038186803b1580156107c457600080fd5b505afa1580156107d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fc91906143b9565b61081957604051633bfe162b60e01b815260040160405180910390fd5b806001600160a01b03166396aaccfe6040518163ffffffff1660e01b815260040160206040518083038186803b15801561085257600080fd5b505afa158015610866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088a919061439c565b6001600160a01b0316336001600160a01b0316146108bb57604051633bfe162b60e01b815260040160405180910390fd5b60085460ff166108de57604051635621fccf60e01b815260040160405180910390fd5b6000889050600080600061092787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061252c92505050565b925092509250606060008b6001600160a01b0316636d1bb8f76040518163ffffffff1660e01b815260040160206040518083038186803b15801561096a57600080fd5b505afa15801561097e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a2919061439c565b6040516001627dd58f60e11b0319815261ffff871660048201526001600160a01b03919091169063ff0454e29060240160206040518083038186803b1580156109ea57600080fd5b505afa1580156109fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a22919061439c565b90506001600160a01b038116610a4b5760405163fb7566d760e01b815260040160405180910390fd5b61ffff85166000908152600a602052604090205460ff16610a7f5760405163334dc1fd60e01b815260040160405180910390fd5b8e610a8d3383838a8f612552565b92505050610af26040518061010001604052808e6001600160a01b031681526020018661ffff1681526020018c8152602001348152602001838152602001876001600160a01b03168152602001846001600160401b03168152602001858152506125c1565b505060018055505050505050505050505050565b610b0f33612870565b610b2c57604051633bfe162b60e01b815260040160405180910390fd5b6000610b72600087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293925050612a0b9050565b90506001600160a01b0381161580610ba9575061ffff8a166000908152600460205260409020546001600160a01b03828116911614155b15610bc757604051637ab628f960e01b815260040160405180910390fd5b6000610c0884848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a7092505050565b905060ff811660021415610c2657610c21858585612a8d565b610c57565b60ff811660011415610c3e57610c218b868686612bf6565b604051630ead561960e11b815260040160405180910390fd5b5050505050505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610cb257600080fd5b505afa158015610cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cea919061439c565b6001600160a01b0316336001600160a01b031614610d1b57604051634b98449160e11b815260040160405180910390fd5b60065481811415610d3f57604051630333a68160e41b815260040160405180910390fd5b60408051828152602081018490527f5cac1093ddd8c1e9cbcd89b2f36fa1889e966cc257753af2d160888564fd9818910160405180910390a150600655565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610dcc57600080fd5b505afa158015610de0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e04919061439c565b6001600160a01b0316336001600160a01b031614610e3557604051634b98449160e11b815260040160405180910390fd5b6007546001600160401b03600160c01b9091048116908216811415610e6d57604051630333a68160e41b815260040160405180910390fd5b604080516001600160401b038084168252841660208201527f7dd9d7c71da5859a7d6e34c00f4889cb529dbbc009a358db124855baa125a4dc910160405180910390a150600780546001600160401b03909216600160c01b026001600160c01b03909216919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015610f2757600080fd5b505afa158015610f3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5f919061439c565b6001600160a01b0316336001600160a01b031614610f9057604051634b98449160e11b815260040160405180910390fd5b6008546001600160a01b036101009091048116908216811415610fc657604051630333a68160e41b815260040160405180910390fd5b604080516001600160a01b038084168252841660208201527f398baf83f237e7e1e1ce6637c69193c52e8b6382036ceb3c6eba08401e327667910160405180910390a150600880546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600260015414156110555760405162461bcd60e51b81526004016106f990614365565b60026001819055506000336001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561109857600080fd5b505afa1580156110ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d0919061439c565b60025460405163c673bdaf60e01b81526001600160a01b03808416600483015292935091169063c673bdaf9060240160206040518083038186803b15801561111757600080fd5b505afa15801561112b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114f91906143b9565b61116c57604051633bfe162b60e01b815260040160405180910390fd5b806001600160a01b03166396aaccfe6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111a557600080fd5b505afa1580156111b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111dd919061439c565b6001600160a01b0316336001600160a01b03161461120e57604051633bfe162b60e01b815260040160405180910390fd5b6000889050600080600061125787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061252c92505050565b925092509250606060008c6001600160a01b0316636d1bb8f76040518163ffffffff1660e01b815260040160206040518083038186803b15801561129a57600080fd5b505afa1580156112ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d2919061439c565b6040516001627dd58f60e11b0319815261ffff871660048201526001600160a01b03919091169063ff0454e29060240160206040518083038186803b15801561131a57600080fd5b505afa15801561132e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611352919061439c565b90506001600160a01b03811661137b5760405163fb7566d760e01b815260040160405180910390fd5b61ffff85166000908152600a602052604090205460ff166113af5760405163334dc1fd60e01b815260040160405180910390fd5b6001600160a01b038c166000908152600960205260409020548f908d908c906113df903390869086908d86612fe0565b945050505050610af26040518061010001604052808e6001600160a01b031681526020018661ffff1681526020018c8152602001348152602001838152602001876001600160a01b03168152602001846001600160401b0316815260200185815250613058565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561149457600080fd5b505afa1580156114a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cc919061439c565b6001600160a01b0316336001600160a01b0316146114fd57604051634b98449160e11b815260040160405180910390fd5b6005548181141561152157604051630333a68160e41b815260040160405180910390fd5b60408051828152602081018490527f83c9ee8eed7101992146d1c75610cc54c1db740210cde12e135fa657a7850854910160405180910390a150600555565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b1580156115ae57600080fd5b505afa1580156115c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e6919061439c565b6001600160a01b0316336001600160a01b03161461161757604051634b98449160e11b815260040160405180910390fd5b6007546001600160401b03600160801b909104811690821681141561164f57604051630333a68160e41b815260040160405180910390fd5b604080516001600160401b038084168252841660208201527fce0317145f704f138aad728eeb9d95c91260950871930acca6e659f1b0883364910160405180910390a150600780546001600160401b03909216600160801b0267ffffffffffffffff60801b19909216919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561170e57600080fd5b505afa158015611722573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611746919061439c565b6001600160a01b0316336001600160a01b03161461177757604051634b98449160e11b815260040160405180910390fd5b6001600160a01b038216600090815260096020526040902054818114156117b157604051630333a68160e41b815260040160405180910390fd5b60408051828152602081018490526001600160a01b038516917ffa622ae921e227a42afec644139331c019f4157c54e93c82dd5f811ba210ac15910160405180910390a2506001600160a01b03909116600090815260096020526040902055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561186057600080fd5b505afa158015611874573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611898919061439c565b6001600160a01b0316336001600160a01b0316146118c957604051634b98449160e11b815260040160405180910390fd5b60085460405160ff90911615808252907f0269774d3426d7e61b04b7d5129948b9f4edf9b937bb0c657fbb32a94a7996ec9060200160405180910390a16008805460ff1916911515919091179055565b6002600154141561193c5760405162461bcd60e51b81526004016106f990614365565b600260015560085461ffff8a1660009081526004602090815260408083205490516001600160a01b0361010090950485169463ab8236f360e01b938f9361198693921691016143db565b60408051601f19818403018152908290526119ae92918c908c908c908c908c90602401614421565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b031990951694909417909352519092506000916119f6913091859101614484565b60408051601f198184030181529082905280516020909101206302902aeb60e41b825291506001600160a01b03841690632902aeb090611a40908f908f908f908f906004016144bc565b60206040518083038186803b158015611a5857600080fd5b505afa158015611a6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9091906144f4565b8114611aaf57604051631c49f4d160e01b815260040160405180910390fd5b600080611af188888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061323892505050565b50935093505050806001600160a01b0316336001600160a01b031614611b2a57604051633bfe162b60e01b815260040160405180910390fd5b856003600084815260200190815260200160002081905550846001600160a01b031663c0e6ac6c8f8f8f8f308a6040518763ffffffff1660e01b8152600401611b789695949392919061450d565b600060405180830381600087803b158015611b9257600080fd5b505af1158015611ba6573d6000803e3d6000fd5b50506001805550505050505050505050505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015611c0c57600080fd5b505afa158015611c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c44919061439c565b6001600160a01b0316336001600160a01b031614611c7557604051634b98449160e11b815260040160405180910390fd5b61ffff82166000908152600460205260409020546001600160a01b03908116908216811415611cb757604051630333a68160e41b815260040160405180910390fd5b6040805161ffff851681526001600160a01b03838116602083015284168183015290517fa0670378b7d4511893529175129417ed82867197a3ea18eb2743483bd4f00c2a9181900360600190a15061ffff91909116600090815260046020526040902080546001600160a01b0319166001600160a01b03909216919091179055565b60085461010090046001600160a01b03163314611d6957604051633bfe162b60e01b815260040160405180910390fd5b600c546001600160a01b0384811691161415611df757600b60009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015611dcf57600080fd5b505af1158015611de3573d6000803e3d6000fd5b5050600b546001600160a01b031695505050505b6000611e038682612a0b565b90506001600160a01b0381161580611e3a575061ffff87166000908152600460205260409020546001600160a01b03828116911614155b15611e5857604051637ab628f960e01b815260040160405180910390fd5b6000611e6383612a70565b905060ff811660011415611e8157611e7c85858561327f565b611e99565b60ff811660021415610c3e57611e7c88868686613342565b5050505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ef157600080fd5b505afa158015611f05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f29919061439c565b6001600160a01b0316336001600160a01b031614611f5a57604051634b98449160e11b815260040160405180910390fd5b6007546001600160401b03908116908216811415611f8b57604051630333a68160e41b815260040160405180910390fd5b604080516001600160401b038084168252841660208201527f1701885e1db4da3ff923033aa465855dde857275866d4f132af5384aa880554f910160405180910390a1506007805467ffffffffffffffff19166001600160401b0392909216919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561204057600080fd5b505afa158015612054573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612078919061439c565b6001600160a01b0316336001600160a01b0316146120a957604051634b98449160e11b815260040160405180910390fd5b61ffff81166000908152600a602090815260409182902054915160ff90921615808352917f0269774d3426d7e61b04b7d5129948b9f4edf9b937bb0c657fbb32a94a7996ec910160405180910390a161ffff919091166000908152600a60205260409020805460ff1916911515919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561216c57600080fd5b505afa158015612180573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121a4919061439c565b6001600160a01b0316336001600160a01b0316146121d557604051634b98449160e11b815260040160405180910390fd5b6007546001600160401b03600160401b909104811690821681141561220d57604051630333a68160e41b815260040160405180910390fd5b604080516001600160401b038084168252841660208201527f8dbd2ecaaca80db9e2e655edc0f1b4df2c87f441eaedf46e0b7b00358d97ad30910160405180910390a150600780546001600160401b03909216600160401b026fffffffffffffffff000000000000000019909216919091179055565b600260015414156122a65760405162461bcd60e51b81526004016106f990614365565b600260018190555060008060006122f286868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506135d792505050565b50945050935093505061230483612870565b61232157604051637c6953f960e01b815260040160405180910390fd5b336001600160a01b0382161461234a57604051633bfe162b60e01b815260040160405180910390fd5b600082815260036020908152604080832087905561ffff8e16835260048252808320549051612385926001600160a01b0390921691016143db565b6040516020818303038152906040529050836001600160a01b031663cfd6528e8d8d8d8d86308f8f8f6040518a63ffffffff1660e01b81526004016123d299989796959493929190614568565b600060405180830381600087803b1580156123ec57600080fd5b505af1158015612400573d6000803e3d6000fd5b5050600180555050505050505050505050505050565b60006124226001613621565b9050801561243a576000805461ff0019166101001790555b6001600160a01b0384166124615760405163fb7566d760e01b815260040160405180910390fd5b6124696136a9565b600280546001600160a01b038087166001600160a01b031992831617909255603260065562030d406005557a0b71b000000000000b71b0000000000007a12000000000000b71b0600755600b8054868416908316179055600c8054928516929091169190911790558015612517576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b6001600160a01b03163b151590565b60008060008380602001905181019061254591906145e2565b9250925092509193909250565b604080516001600160a01b038781166020830152868116828401526060808301879052908516608083015260a08083018590528351808403909101815260c08301909352916125a7916002919060e00161461a565b604051602081830303815290604052905095945050505050565b6125e560405180606001604052806000815260200160008152602001606081525090565b60208083015161ffff1660009081526004825260408082205490519192612618926001600160a01b0390921691016143db565b60408051601f19818403018152919052905060006126368282612a0b565b6001600160a01b0316141561265e5760405163fb7566d760e01b815260040160405180910390fd5b60405180606001604052808460c001516001600160401b031681526020018460e00151815260200160008560e00151116126b2576040805160006020820152016040516020818303038152906040526126b4565b825b905283516001600160a01b031660009081526009602052604081205460065492945091612710906126e5908261464c565b86604001516126f49190614663565b6126fe9190614682565b6080860151600854600b54885193945091926001600160a01b03610100909204821692908216911614156127b357600b546040808901519051632e1a7d4d60e01b81526001600160a01b0390921691632e1a7d4d916127639160040190815260200190565b600060405180830381600087803b15801561277d57600080fd5b505af1158015612791573d6000803e3d6000fd5b505050508660400151876060018181516127ab91906146a4565b9052506127e8565b86516127ca906001600160a01b03168260006136da565b604087015187516127e8916001600160a01b039091169083906136da565b806001600160a01b0316639fbf10fc8860600151896020015187888c60a001518d604001518a8e8e8c6040518b63ffffffff1660e01b8152600401612835999897969594939291906146bc565b6000604051808303818588803b15801561284e57600080fd5b505af1158015612862573d6000803e3d6000fd5b505050505050505050505050565b600080826001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b1580156128ac57600080fd5b505afa1580156128c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e4919061439c565b600254604051631a0dd00b60e01b81526001600160a01b038084166004830152929350911690631a0dd00b9060240160206040518083038186803b15801561292b57600080fd5b505afa15801561293f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296391906143b9565b6129705750600092915050565b806001600160a01b0316636d1bb8f76040518163ffffffff1660e01b815260040160206040518083038186803b1580156129a957600080fd5b505afa1580156129bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e1919061439c565b6001600160a01b0316836001600160a01b031614612a025750600092915050565b50600192915050565b6000612a188260146146a4565b83511015612a605760405162461bcd60e51b8152602060048201526015602482015274746f416464726573735f6f75744f66426f756e647360581b60448201526064016106f9565b500160200151600160601b900490565b600081806020019051810190612a86919061474a565b5092915050565b6000806000612ad185858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061382592505050565b9250925092506000836001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612b1257600080fd5b505afa158015612b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b4a919061439c565b9050612b616001600160a01b0382168460006136da565b612b756001600160a01b03821684896136da565b604051636455bf6f60e01b815260048101839052602481018890526001600160a01b03841690636455bf6f90604401602060405180830381600087803b158015612bbe57600080fd5b505af1158015612bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9991906144f4565b600080600080600080612c3e88888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506135d792505050565b9550955095509550955095506000600860019054906101000a90046001600160a01b03166001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9a57600080fd5b505afa158015612cae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cd2919061439c565b6001600160a01b031663068bcd8d856040518263ffffffff1660e01b8152600401612cff91815260200190565b60206040518083038186803b158015612d1757600080fd5b505afa158015612d2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4f919061439c565b6001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8757600080fd5b505afa158015612d9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbf919061439c565b600c549091506001600160a01b0380831691161415612de65750600b546001600160a01b03165b612e6385876001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b158015612e2357600080fd5b505afa158015612e37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5b919061439c565b838d86613857565b995060008b9050612862604051806101000160405280846001600160a01b031681526020018361ffff1681526020018d8152602001600260009054906101000a90046001600160a01b03166001600160a01b031663c6bbd5a76040518163ffffffff1660e01b815260040160206040518083038186803b158015612ee657600080fd5b505afa158015612efa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f1e919061439c565b60405163d81e47d360e01b815261ffff861660048201526001600160a01b03919091169063d81e47d39060240160206040518083038186803b158015612f6357600080fd5b505afa158015612f77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9b91906144f4565b8152602001612faa8b8a6139ca565b81526001600160a01b0387166020820152600754600160801b90046001600160401b0316604082015260006060909101526125c1565b604080516001600160a01b0388811660208301528781168284015260608083018890526080830187905290851660a083015260c08083018590528351808403909101815260e083019093529161303d91600191906101000161461a565b60405160208183030381529060405290509695505050505050565b60208082015161ffff166000908152600490915260409020546001600160a01b0316806130985760405163fb7566d760e01b815260040160405180910390fd5b600060028360c001516001600160401b03166005546130b791906146a4565b60e0850151806130c85760006130ca565b845b604051602001613114949392919060f09490941b6001600160f01b03191684526002840192909252602283015260601b6bffffffffffffffffffffffff1916604282015260560190565b604051602081830303815290604052905082600001516001600160a01b0316636d1bb8f76040518163ffffffff1660e01b815260040160206040518083038186803b15801561316257600080fd5b505afa158015613176573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319a919061439c565b6001600160a01b031663e7f0c59f8460600151308660200151866040516020016131c491906143db565b60408051601f19818403018152828252908a015160808b015160c08c015160a08d01516001600160e01b031960e08b901b16865261320b9796956000908d906004016147dc565b6000604051808303818588803b15801561322457600080fd5b505af1158015611e99573d6000803e3d6000fd5b600080600080600085806020019051810190613254919061474a565b805190975061326d91508701602090810190880161485a565b939a9299509097509550909350915050565b60008061328b83613a1b565b90925090506132a56001600160a01b0386168360006136da565b6132b96001600160a01b03861683866136da565b6040516320159ddd60e21b815260048101829052602481018590526001600160a01b03831690638056777490604401602060405180830381600087803b15801561330257600080fd5b505af1158015613316573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061333a91906144f4565b505050505050565b600080600080600061335386613238565b945094509450945094506000846001600160a01b031663fc0c546a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561339857600080fd5b505afa1580156133ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133d0919061439c565b90506133df848a838b86613857565b6040516001627dd58f60e11b0319815261ffff8c1660048201529098508a906000906001600160a01b0388169063ff0454e29060240160206040518083038186803b15801561342d57600080fd5b505afa158015613441573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613465919061439c565b9050612862604051806101000160405280856001600160a01b031681526020018461ffff1681526020018c8152602001600260009054906101000a90046001600160a01b03166001600160a01b031663c6bbd5a76040518163ffffffff1660e01b815260040160206040518083038186803b1580156134e357600080fd5b505afa1580156134f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351b919061439c565b60405163665471cd60e11b815261ffff871660048201526001600160a01b03919091169063cca8e39a9060240160206040518083038186803b15801561356057600080fd5b505afa158015613574573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359891906144f4565b81526020016135a8848c8b613a54565b81526001600160a01b03881660208201526007546001600160401b031660408201526000606090910152613058565b600080600080600080868060200190518101906135f4919061474a565b805190985061360d9150880160209081019089016148bb565b949c939b5091995097509550909350915050565b60008054610100900460ff1615613668578160ff1660011480156136445750303b155b6136605760405162461bcd60e51b81526004016106f990614925565b506000919050565b60005460ff80841691161061368f5760405162461bcd60e51b81526004016106f990614925565b506000805460ff191660ff92909216919091179055600190565b600054610100900460ff166136d05760405162461bcd60e51b81526004016106f990614973565b6136d8613ab0565b565b8015806137635750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561372957600080fd5b505afa15801561373d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376191906144f4565b155b6137ce5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016106f9565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052613820908490613add565b505050565b60008060008380602001905181019061383e919061474a565b80519095506125459150850160209081019086016149be565b600085815260036020526040812054801561387f576000878152600360205260408120559150815b60025460408051632b3297f960e01b815290516000926001600160a01b031691632b3297f9916004808301926020929190829003018186803b1580156138c457600080fd5b505afa1580156138d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138fc919061439c565b90506139136001600160a01b0388168260006136da565b6139276001600160a01b03881682876136da565b604051636ccb2b0160e01b81526001600160a01b03888116600483015287811660248301526044820187905260648201869052306084830152821690636ccb2b019060a401602060405180830381600087803b15801561398657600080fd5b505af115801561399a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139be91906144f4565b98975050505050505050565b604080516001600160a01b03841660208201528082018390528151808203830181526060808301909352613a04916001919060800161461a565b604051602081830303815290604052905092915050565b60008082806020019051810190613a32919061474a565b8051909450613a4b915084016020908101908501614a01565b91509150915091565b604080516001600160a01b03858116602083015284168183015260608082018490528251808303820181526080830190935291613a97916002919060a00161461a565b60405160208183030381529060405290505b9392505050565b600054610100900460ff16613ad75760405162461bcd60e51b81526004016106f990614973565b60018055565b6000613b32826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613baf9092919063ffffffff16565b8051909150156138205780806020019051810190613b5091906143b9565b6138205760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016106f9565b6060613bbe8484600085613bc6565b949350505050565b606082471015613c275760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016106f9565b6001600160a01b0385163b613c7e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106f9565b600080866001600160a01b03168587604051613c9a9190614a2f565b60006040518083038185875af1925050503d8060008114613cd7576040519150601f19603f3d011682016040523d82523d6000602084013e613cdc565b606091505b5091509150613cec828286613cf7565b979650505050505050565b60608315613d06575081613aa9565b825115613d165782518084602001fd5b8160405162461bcd60e51b81526004016106f99190614352565b6001600160a01b0381168114613d4557600080fd5b50565b60008083601f840112613d5a57600080fd5b5081356001600160401b03811115613d7157600080fd5b602083019150836020828501011115613d8957600080fd5b9250929050565b60008060008060008060008060e0898b031215613dac57600080fd5b883597506020890135613dbe81613d30565b96506040890135613dce81613d30565b95506060890135613dde81613d30565b94506080890135935060a0890135925060c08901356001600160401b03811115613e0757600080fd5b613e138b828c01613d48565b999c989b5096995094979396929594505050565b61ffff81168114613d4557600080fd5b6001600160401b0381168114613d4557600080fd5b600080600080600080600080600060c08a8c031215613e6a57600080fd5b8935613e7581613e27565b985060208a01356001600160401b0380821115613e9157600080fd5b613e9d8d838e01613d48565b909a50985060408c01359150613eb282613e37565b90965060608b01359080821115613ec857600080fd5b613ed48d838e01613d48565b909750955060808c0135945060a08c0135915080821115613ef457600080fd5b50613f018c828d01613d48565b915080935050809150509295985092959850929598565b600060208284031215613f2a57600080fd5b5035919050565b600060208284031215613f4357600080fd5b8135613aa981613e37565b600060208284031215613f6057600080fd5b8135613aa981613d30565b60008060408385031215613f7e57600080fd5b8235613f8981613d30565b946020939093013593505050565b600080600080600080600080600060e08a8c031215613fb557600080fd5b8935613fc081613e27565b985060208a01356001600160401b0380821115613fdc57600080fd5b613fe88d838e01613d48565b909a50985060408c01359150613ffd82613e37565b90965060608b01359061400f82613d30565b90955060808b0135945060a08b0135908082111561402c57600080fd5b506140398c828d01613d48565b9a9d999c50979a9699959894979660c00135949350505050565b6000806040838503121561406657600080fd5b823561407181613e27565b9150602083013561408181613d30565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156140ca576140ca61408c565b604052919050565b60006001600160401b038211156140eb576140eb61408c565b50601f01601f191660200190565b600082601f83011261410a57600080fd5b813561411d614118826140d2565b6140a2565b81815284602083860101111561413257600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c0878903121561416857600080fd5b863561417381613e27565b955060208701356001600160401b038082111561418f57600080fd5b61419b8a838b016140f9565b965060408901359550606089013591506141b482613d30565b9093506080880135925060a088013590808211156141d157600080fd5b506141de89828a016140f9565b9150509295509295509295565b6000602082840312156141fd57600080fd5b8135613aa981613e27565b60008060008060008060008060c0898b03121561422457600080fd5b883561422f81613e27565b975060208901356001600160401b038082111561424b57600080fd5b6142578c838d01613d48565b909950975060408b0135915061426c82613e37565b90955060608a0135945060808a0135908082111561428957600080fd5b506142968b828c01613d48565b999c989b50969995989497949560a00135949350505050565b6000806000606084860312156142c457600080fd5b83356142cf81613d30565b925060208401356142df81613d30565b915060408401356142ef81613d30565b809150509250925092565b60005b838110156143155781810151838201526020016142fd565b838111156125175750506000910152565b6000815180845261433e8160208601602086016142fa565b601f01601f19169290920160200192915050565b602081526000613aa96020830184614326565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6000602082840312156143ae57600080fd5b8151613aa981613d30565b6000602082840312156143cb57600080fd5b81518015158114613aa957600080fd5b60609190911b6bffffffffffffffffffffffff1916815260140190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61ffff8816815260c06020820152600061443e60c0830189614326565b6001600160401b03881660408401526001600160a01b03871660608401526080830186905282810360a08401526144768185876143f8565b9a9950505050505050505050565b6bffffffffffffffffffffffff198360601b168152600082516144ae8160148501602087016142fa565b919091016014019392505050565b61ffff851681526060602082015260006144da6060830185876143f8565b90506001600160401b038316604083015295945050505050565b60006020828403121561450657600080fd5b5051919050565b61ffff8716815260a06020820152600061452b60a0830187896143f8565b6001600160401b03861660408401526001600160a01b0385166060840152828103608084015261455b8185614326565b9998505050505050505050565b61ffff8a16815260e06020820152600061458660e083018a8c6143f8565b6001600160401b038916604084015282810360608401526145a78189614326565b6001600160a01b038816608085015260a0840187905283810360c085015290506145d28185876143f8565b9c9b505050505050505050505050565b6000806000606084860312156145f757600080fd5b835161460281613e27565b6020850151604086015191945092506142ef81613e37565b60ff83168152604060208201526000613bbe6040830184614326565b634e487b7160e01b600052601160045260246000fd5b60008282101561465e5761465e614636565b500390565b600081600019048311821515161561467d5761467d614636565b500290565b60008261469f57634e487b7160e01b600052601260045260246000fd5b500490565b600082198211156146b7576146b7614636565b500190565b600061012061ffff8c1683528a602084015289604084015260018060a01b03891660608401528760808401528660a08401528060c084015285518184015250602085015161014083015260408501516060610160840152614721610180840182614326565b905082810360e08401526147358186614326565b90508281036101008401526145d28185614326565b6000806040838503121561475d57600080fd5b825160ff8116811461476e57600080fd5b60208401519092506001600160401b0381111561478a57600080fd5b8301601f8101851361479b57600080fd5b80516147a9614118826140d2565b8181528660208385010111156147be57600080fd5b6147cf8260208301602086016142fa565b8093505050509250929050565b6001600160a01b038a8116825261ffff8a1660208301526101206040830181905260009161480c8483018c614326565b91508960608501528382036080850152614826828a614326565b6001600160401b03891660a086015287821660c086015290861660e085015283810361010085015290506145d28185614326565b600080600080600060a0868803121561487257600080fd5b855161487d81613d30565b602087015190955061488e81613d30565b6040870151606088015191955093506148a681613d30565b80925050608086015190509295509295909350565b60008060008060008060c087890312156148d457600080fd5b86516148df81613d30565b60208801519096506148f081613d30565b809550506040870151935060608701519250608087015161491081613d30565b8092505060a087015190509295509295509295565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000806000606084860312156149d357600080fd5b83516149de81613d30565b60208501519093506149ef81613d30565b80925050604084015190509250925092565b60008060408385031215614a1457600080fd5b8251614a1f81613d30565b6020939093015192949293505050565b60008251614a418184602087016142fa565b919091019291505056fea26469706673582212205c2b013588d662f1788335f277c81bde3395dfcb769803875155cb83f22cf5e364736f6c63430008090033

Block Transaction Difficulty 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
Loading...
Loading
Loading...
Loading
Loading...
Loading

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.