ETH Price: $1,975.71 (+0.36%)
 

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer242618172026-01-18 13:03:4734 days ago1768741427IN
0xBbcb9144...04A7b6e00
1 wei0.00000060.02885808
Transfer242618112026-01-18 13:02:3534 days ago1768741355IN
0xBbcb9144...04A7b6e00
8 wei0.000000680.032674
Transfer242618012026-01-18 13:00:3534 days ago1768741235IN
0xBbcb9144...04A7b6e00
1 wei0.000000670.0320722
Transfer242617932026-01-18 12:58:5934 days ago1768741139IN
0xBbcb9144...04A7b6e00
1 wei0.000000810.03850066
Transfer242617812026-01-18 12:56:3534 days ago1768740995IN
0xBbcb9144...04A7b6e00
4 wei0.000000710.03404536
Transfer242617702026-01-18 12:54:2334 days ago1768740863IN
0xBbcb9144...04A7b6e00
9 wei0.000000710.03383353
Transfer242617702026-01-18 12:54:2334 days ago1768740863IN
0xBbcb9144...04A7b6e00
5 wei0.000000710.03383353
Transfer242617612026-01-18 12:52:3534 days ago1768740755IN
0xBbcb9144...04A7b6e00
2 wei0.000000680.03272664
Transfer242617582026-01-18 12:51:5934 days ago1768740719IN
0xBbcb9144...04A7b6e00
3 wei0.000000690.0328803
Transfer242617192026-01-18 12:44:1134 days ago1768740251IN
0xBbcb9144...04A7b6e00
8 wei0.000000620.02975105
Transfer242617192026-01-18 12:44:1134 days ago1768740251IN
0xBbcb9144...04A7b6e00
8 wei0.000000620.02975105
Transfer242617152026-01-18 12:43:2334 days ago1768740203IN
0xBbcb9144...04A7b6e00
3 wei0.000000680.0326452
Transfer242617112026-01-18 12:42:3534 days ago1768740155IN
0xBbcb9144...04A7b6e00
5 wei0.000000690.03319346
Transfer242616932026-01-18 12:38:5934 days ago1768739939IN
0xBbcb9144...04A7b6e00
1 wei0.000000670.03196322
Transfer242616852026-01-18 12:37:2334 days ago1768739843IN
0xBbcb9144...04A7b6e00
2 wei0.000000640.03070374
Transfer242616542026-01-18 12:31:1134 days ago1768739471IN
0xBbcb9144...04A7b6e00
8 wei0.00000070.03347826
Transfer242616482026-01-18 12:29:5934 days ago1768739399IN
0xBbcb9144...04A7b6e00
3 wei0.000000720.03463808
Transfer242616382026-01-18 12:27:5934 days ago1768739279IN
0xBbcb9144...04A7b6e00
2 wei0.000000690.03320474
Transfer242616172026-01-18 12:23:4734 days ago1768739027IN
0xBbcb9144...04A7b6e00
9 wei0.000000710.03411037
Transfer242616172026-01-18 12:23:4734 days ago1768739027IN
0xBbcb9144...04A7b6e00
7 wei0.000000710.03411037
Transfer242616082026-01-18 12:21:5934 days ago1768738919IN
0xBbcb9144...04A7b6e00
4 wei0.000000670.03210315
Transfer242616052026-01-18 12:21:2334 days ago1768738883IN
0xBbcb9144...04A7b6e00
1 wei0.000000660.03150005
Transfer242616052026-01-18 12:21:2334 days ago1768738883IN
0xBbcb9144...04A7b6e00
1 wei0.000000660.03150005
Transfer242615992026-01-18 12:20:1134 days ago1768738811IN
0xBbcb9144...04A7b6e00
5 wei0.000000670.03213005
Transfer242615802026-01-18 12:16:2334 days ago1768738583IN
0xBbcb9144...04A7b6e00
7 wei0.000000680.03236216
View all transactions

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
Swap Single239358932025-12-03 22:33:5980 days ago1764801239
0xBbcb9144...04A7b6e00
0.0039 ETH
0x60c06040230430412025-08-01 1:46:23205 days ago1754012783  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FluidDexLite

Compiler Version
v0.8.29+commit.ab55807c

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

import "./coreInternals.sol";

/// @title FluidDexLite
contract FluidDexLite is CoreInternals {
    constructor(address auth_, address liquidity_, address deployerContract_) {
        _isAuth[auth_] = 1;
        LIQUIDITY = IFluidLiquidity(liquidity_);
        DEPLOYER_CONTRACT = deployerContract_;
    }

    /// @notice Swap through a single dex pool
    /// @dev Uses _swapIn for positive amountSpecified_ (user provides input), _swapOut for negative (user receives output).
    /// @param dexKey_ The dex pool to swap through.
    /// @param swap0To1_ Whether to swap from token0 to token1 or vice versa.
    /// @param amountSpecified_ The amount to swap (positive for exact input, negative for exact output).
    /// @param amountLimit_ The minimum/maximum amount for the unspecified side.
    /// @param to_ The recipient address.
    function swapSingle(
        DexKey calldata dexKey_, 
        bool swap0To1_, 
        int256 amountSpecified_,
        uint256 amountLimit_,
        address to_,
        bool isCallback_,
        bytes calldata callbackData_,
        bytes calldata extraData_
    ) external payable _reentrancyLock returns (uint256 amountUnspecified_) {
        if (amountSpecified_ > 0) {
            amountUnspecified_ = _swapIn(dexKey_, swap0To1_, uint256(amountSpecified_));

            if (amountUnspecified_ < amountLimit_) {
                revert AmountLimitNotMet(amountUnspecified_, amountLimit_);
            }

            if (extraData_.length == 0) {
                if (swap0To1_) {
                    _transferTokens(dexKey_.token0, uint256(amountSpecified_), dexKey_.token1, amountUnspecified_, to_, isCallback_, callbackData_);
                } else {
                    _transferTokens(dexKey_.token1, uint256(amountSpecified_), dexKey_.token0, amountUnspecified_, to_, isCallback_, callbackData_);
                }
            } else if (bytes32(extraData_) == ESTIMATE_SWAP) {
                revert EstimateSwap(amountUnspecified_);
            } else {
                _callExtraDataSlot(
                    abi.encode(
                        SWAP_SINGLE, 
                        abi.encode(dexKey_, swap0To1_, amountSpecified_, amountUnspecified_, extraData_)
                    )
                );
            }
        } else {
            amountUnspecified_ = _swapOut(dexKey_, swap0To1_, uint256(-amountSpecified_));

            if (amountUnspecified_ > amountLimit_) {
                revert AmountLimitExceeded(amountUnspecified_, amountLimit_);
            }

            if (extraData_.length == 0) {
                if (swap0To1_) {
                    _transferTokens(dexKey_.token0, amountUnspecified_, dexKey_.token1, uint256(-amountSpecified_), to_, isCallback_, callbackData_);
                } else {
                    _transferTokens(dexKey_.token1, amountUnspecified_, dexKey_.token0, uint256(-amountSpecified_), to_, isCallback_, callbackData_);
                }
            } else if (bytes32(extraData_) == ESTIMATE_SWAP) {
                revert EstimateSwap(amountUnspecified_);
            } else {
                _callExtraDataSlot(
                    abi.encode(
                        SWAP_SINGLE, 
                        abi.encode(dexKey_, swap0To1_, amountSpecified_, amountUnspecified_, extraData_)
                    )
                );
            }
        }
    }

    /// @notice Swap through a path of dex pools
    /// @dev Uses _swapIn for positive amountSpecified_ (user provides input), _swapOut for negative (user receives output).
    /// @param path_ The path of the swap.
    /// @param dexKeys_ The dex pools to swap through.
    /// @param amountSpecified_ The amount to swap (positive for exact input, negative for exact output).
    /// @param amountLimits_ The minimum/maximum amount for the unspecified side for all swaps.
    /// @param transferParams_ The parameters for the transfer.
    /// @return amountUnspecified_ The amount of the unspecified token.
    function swapHop(
        address[] calldata path_,
        DexKey[] calldata dexKeys_,
        int256 amountSpecified_,
        uint256[] calldata amountLimits_,
        TransferParams calldata transferParams_
    ) external payable _reentrancyLock returns (uint256 amountUnspecified_) {
        if (dexKeys_.length == 0) {
            revert EmptyDexKeysArray();
        }
        if (path_.length - 1 != dexKeys_.length) {
            revert InvalidPathLength(path_.length, dexKeys_.length);
        }
        if (amountLimits_.length != dexKeys_.length) {
            revert InvalidAmountLimitsLength(amountLimits_.length, dexKeys_.length);
        }

        if (amountSpecified_ > 0) {
            // Swap In (Exact input amount provided by the user)
            amountUnspecified_ = uint256(amountSpecified_);

            for (uint256 i = 0; i < dexKeys_.length; ) {
                bool swap0To1_;
                unchecked {
                    if (path_[i] == dexKeys_[i].token0 && path_[i + 1] == dexKeys_[i].token1) {
                        swap0To1_ = true;
                    } else if (path_[i] == dexKeys_[i].token1 && path_[i + 1] == dexKeys_[i].token0) {
                        swap0To1_ = false;
                    } else {
                        revert InvalidPathTokenOrder();
                    }
                }

                amountUnspecified_ = _swapIn(dexKeys_[i], swap0To1_, amountUnspecified_);
                if (amountUnspecified_ < amountLimits_[i]) {
                    revert AmountLimitNotMet(amountUnspecified_, amountLimits_[i]);
                }

                unchecked { ++i; }
            }

            if (transferParams_.extraData.length == 0) {
                _transferTokens(
                    path_[0], 
                    uint256(amountSpecified_), 
                    path_[dexKeys_.length], 
                    amountUnspecified_, 
                    transferParams_.to, 
                    transferParams_.isCallback, 
                    transferParams_.callbackData
                );
            } else if (bytes32(transferParams_.extraData) == ESTIMATE_SWAP) {
                revert EstimateSwap(amountUnspecified_);
            } else {
                _callExtraDataSlot(
                    abi.encode(
                        SWAP_HOP, 
                        abi.encode(path_, dexKeys_, amountSpecified_, amountUnspecified_, transferParams_.extraData)
                    )
                );
            }
                
        } else {
            // Swap Out (Exact output amount received by the user)
            amountUnspecified_ = uint256(-amountSpecified_);

            for (uint256 i = dexKeys_.length; i > 0; ) {
                bool swap0To1_;
                unchecked {
                    if (path_[i - 1] == dexKeys_[i - 1].token0 && path_[i] == dexKeys_[i - 1].token1) {
                        swap0To1_ = true;
                    } else if (path_[i - 1] == dexKeys_[i - 1].token1 && path_[i] == dexKeys_[i - 1].token0) {
                        swap0To1_ = false;
                    } else {
                        revert InvalidPathTokenOrder();
                    }
                }

                amountUnspecified_ = _swapOut(dexKeys_[i - 1], swap0To1_, amountUnspecified_);
                if (amountUnspecified_ > amountLimits_[i - 1]) {
                    revert AmountLimitExceeded(amountUnspecified_, amountLimits_[i - 1]);
                }

                unchecked { --i; }
            }

            if (transferParams_.extraData.length == 0) {
                _transferTokens(
                    path_[0], 
                    amountUnspecified_, 
                    path_[dexKeys_.length], 
                    uint256(-amountSpecified_), 
                    transferParams_.to, 
                    transferParams_.isCallback, 
                    transferParams_.callbackData
                );
            } else if (bytes32(transferParams_.extraData) == ESTIMATE_SWAP) {
                revert EstimateSwap(amountUnspecified_);
            } else {
                _callExtraDataSlot(
                    abi.encode(
                        SWAP_HOP, 
                        abi.encode(path_, dexKeys_, amountSpecified_, amountUnspecified_, transferParams_.extraData)
                    )
                );
            }
        }
    }

    function readFromStorage(bytes32 slot_) external view returns (uint256 result_) {
        assembly {
            result_ := sload(slot_)
        }
    }

    fallback(bytes calldata data_) external payable _reentrancyLock returns (bytes memory) {
        if (_isAuth[msg.sender] != 1 && _getGovernanceAddr() != msg.sender) {
            revert UnauthorizedCaller(msg.sender);
        }

        (address target_, bytes memory spellData_) = abi.decode(data_, (address, bytes));
        return _spell(target_, spellData_);
    }

    receive() external payable {}
}

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21 <=0.8.29;

interface IProxy {
    function setAdmin(address newAdmin_) external;

    function setDummyImplementation(address newDummyImplementation_) external;

    function addImplementation(address implementation_, bytes4[] calldata sigs_) external;

    function removeImplementation(address implementation_) external;

    function getAdmin() external view returns (address);

    function getDummyImplementation() external view returns (address);

    function getImplementationSigs(address impl_) external view returns (bytes4[] memory);

    function getSigsImplementation(bytes4 sig_) external view returns (address);

    function readFromStorage(bytes32 slot_) external view returns (uint256 result_);
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.21 <=0.8.29;

/// @notice implements calculation of address for contracts deployed through CREATE.
/// Accepts contract deployed from which address & nonce
library AddressCalcs {

    /// @notice                         Computes the address of a contract based
    /// @param deployedFrom_            Address from which the contract was deployed
    /// @param nonce_                   Nonce at which the contract was deployed
    /// @return contract_               Address of deployed contract
    function addressCalc(address deployedFrom_, uint nonce_) internal pure returns (address contract_) {
        // @dev based on https://ethereum.stackexchange.com/a/61413

        // nonce of smart contract always starts with 1. so, with nonce 0 there won't be any deployment
        // hence, nonce of vault deployment starts with 1.
        bytes memory data;
        if (nonce_ == 0x00) {
            return address(0);
        } else if (nonce_ <= 0x7f) {
            data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployedFrom_, uint8(nonce_));
        } else if (nonce_ <= 0xff) {
            data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployedFrom_, bytes1(0x81), uint8(nonce_));
        } else if (nonce_ <= 0xffff) {
            data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployedFrom_, bytes1(0x82), uint16(nonce_));
        } else if (nonce_ <= 0xffffff) {
            data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployedFrom_, bytes1(0x83), uint24(nonce_));
        } else {
            data = abi.encodePacked(bytes1(0xda), bytes1(0x94), deployedFrom_, bytes1(0x84), uint32(nonce_));
        }

        return address(uint160(uint256(keccak256(data))));
    }

}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.21 <=0.8.29;

/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.
/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision
/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can
/// result in significant gas cost reduction due to storage space reduction.
/// Also note, a valid big number is as follows: if the exponent is > 0, then coefficient last bits should be occupied to have max precision.
/// @dev roundUp is more like a increase 1, which happens everytime for the same number.
/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.
library BigMathMinified {
    /// @dev constants to use for `roundUp` input param to increase readability
    bool internal constant ROUND_DOWN = false;
    bool internal constant ROUND_UP = true;

    /// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).
    /// e.g.:
    /// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]
    /// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)
    ///                                     => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000
    ///                                                                        ^-------------------- 51(exponent) -------------- ^
    /// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011               (2236301563)
    /// exponent =                                            0011,0011     (51)
    /// bigNumber =   1000,0101,0100,1011,0100,0000,1111,1011,0011,0011     (572493200179)
    ///
    /// @param normal number which needs to be converted into Big Number
    /// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))
    /// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))
    /// @param roundUp signals if result should be rounded down or up
    /// @return bigNumber converted bigNumber (coefficient << exponent)
    function toBigNumber(
        uint256 normal,
        uint256 coefficientSize,
        uint256 exponentSize,
        bool roundUp
    ) internal pure returns (uint256 bigNumber) {
        assembly {
            let lastBit_
            let number_ := normal
            if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
                number_ := shr(0x80, number_)
                lastBit_ := 0x80
            }
            if gt(number_, 0xFFFFFFFFFFFFFFFF) {
                number_ := shr(0x40, number_)
                lastBit_ := add(lastBit_, 0x40)
            }
            if gt(number_, 0xFFFFFFFF) {
                number_ := shr(0x20, number_)
                lastBit_ := add(lastBit_, 0x20)
            }
            if gt(number_, 0xFFFF) {
                number_ := shr(0x10, number_)
                lastBit_ := add(lastBit_, 0x10)
            }
            if gt(number_, 0xFF) {
                number_ := shr(0x8, number_)
                lastBit_ := add(lastBit_, 0x8)
            }
            if gt(number_, 0xF) {
                number_ := shr(0x4, number_)
                lastBit_ := add(lastBit_, 0x4)
            }
            if gt(number_, 0x3) {
                number_ := shr(0x2, number_)
                lastBit_ := add(lastBit_, 0x2)
            }
            if gt(number_, 0x1) {
                lastBit_ := add(lastBit_, 1)
            }
            if gt(number_, 0) {
                lastBit_ := add(lastBit_, 1)
            }
            if lt(lastBit_, coefficientSize) {
                // for throw exception
                lastBit_ := coefficientSize
            }
            let exponent := sub(lastBit_, coefficientSize)
            let coefficient := shr(exponent, normal)
            if and(roundUp, gt(exponent, 0)) {
                // rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number
                coefficient := add(coefficient, 1)
                if eq(shl(coefficientSize, 1), coefficient) {
                    // case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits
                    // final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.
                    coefficient := shl(sub(coefficientSize, 1), 1)
                    exponent := add(exponent, 1)
                }
            }
            if iszero(lt(exponent, shl(exponentSize, 1))) {
                // if exponent is >= exponentSize, the normal number is too big to fit within
                // BigNumber with too small sizes for coefficient and exponent
                revert(0, 0)
            }
            bigNumber := shl(exponentSize, coefficient)
            bigNumber := add(bigNumber, exponent)
        }
    }

    /// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`
    function fromBigNumber(
        uint256 bigNumber,
        uint256 exponentSize,
        uint256 exponentMask
    ) internal pure returns (uint256 normal) {
        assembly {
            let coefficient := shr(exponentSize, bigNumber)
            let exponent := and(bigNumber, exponentMask)
            normal := shl(exponent, coefficient)
        }
    }

    /// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).
    /// e.g.
    /// 5035703444687813576399584 = 10000101010010110100000011111011110010100110100000000011100101001101001101011100000
    /// lastBit =                   ^---------------------------------   83   ----------------------------------------^
    function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {
        assembly {
            let number_ := normal
            if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
                number_ := shr(0x80, number_)
                lastBit := 0x80
            }
            if gt(number_, 0xFFFFFFFFFFFFFFFF) {
                number_ := shr(0x40, number_)
                lastBit := add(lastBit, 0x40)
            }
            if gt(number_, 0xFFFFFFFF) {
                number_ := shr(0x20, number_)
                lastBit := add(lastBit, 0x20)
            }
            if gt(number_, 0xFFFF) {
                number_ := shr(0x10, number_)
                lastBit := add(lastBit, 0x10)
            }
            if gt(number_, 0xFF) {
                number_ := shr(0x8, number_)
                lastBit := add(lastBit, 0x8)
            }
            if gt(number_, 0xF) {
                number_ := shr(0x4, number_)
                lastBit := add(lastBit, 0x4)
            }
            if gt(number_, 0x3) {
                number_ := shr(0x2, number_)
                lastBit := add(lastBit, 0x2)
            }
            if gt(number_, 0x1) {
                lastBit := add(lastBit, 1)
            }
            if gt(number_, 0) {
                lastBit := add(lastBit, 1)
            }
        }
    }

    /// @dev gets the least significant bit `firstBit` of a `normal` number (position of rightmost 1 in binary format).
    /// e.g.
    /// 5035703444687813576399584 = 10000101010010110100000011111011110010100110100000000011100101001101001101011100000
    /// firstBit =                                                                                               ^-6--^
    function leastSignificantBit(uint256 normal) internal pure returns (uint firstBit) {
        assembly {
            // If number is 0, revert as there is no least significant bit
            if iszero(normal) {
                revert(0, 0)
            }

            // Find first set bit using binary search
            let number_ := normal
            firstBit := 0

            // Check if lower 128 bits are all zero
            if iszero(and(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) {
                number_ := shr(0x80, number_)
                firstBit := 0x80
            }
            // Check if lower 64 bits are all zero
            if iszero(and(number_, 0xFFFFFFFFFFFFFFFF)) {
                number_ := shr(0x40, number_)
                firstBit := add(firstBit, 0x40)
            }
            // Check if lower 32 bits are all zero
            if iszero(and(number_, 0xFFFFFFFF)) {
                number_ := shr(0x20, number_)
                firstBit := add(firstBit, 0x20)
            }
            // Check if lower 16 bits are all zero
            if iszero(and(number_, 0xFFFF)) {
                number_ := shr(0x10, number_)
                firstBit := add(firstBit, 0x10)
            }
            // Check if lower 8 bits are all zero
            if iszero(and(number_, 0xFF)) {
                number_ := shr(0x8, number_)
                firstBit := add(firstBit, 0x8)
            }
            // Check if lower 4 bits are all zero
            if iszero(and(number_, 0xF)) {
                number_ := shr(0x4, number_)
                firstBit := add(firstBit, 0x4)
            }
            // Check if lower 2 bits are all zero
            if iszero(and(number_, 0x3)) {
                number_ := shr(0x2, number_)
                firstBit := add(firstBit, 0x2)
            }
            // Check if lowest bit is zero
            if iszero(and(number_, 0x1)) {
                firstBit := add(firstBit, 1)
            }
            // Add 1 to match the 1-based position counting
            firstBit := add(firstBit, 1)
        }
    }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

/// @notice library that helps in reading / working with storage slot data of Fluid Dex Lite.
library DexLiteSlotsLink {
    /// @dev storage slot for is auth mapping
    uint256 internal constant DEX_LITE_IS_AUTH_SLOT = 0;
    /// @dev storage slot for dexes list
    uint256 internal constant DEX_LITE_DEXES_LIST_SLOT = 1;
    /// @dev storage slot for is dex variables
    uint256 internal constant DEX_LITE_DEX_VARIABLES_SLOT = 2;
    /// @dev storage slot for center price shift
    uint256 internal constant DEX_LITE_CENTER_PRICE_SHIFT_SLOT = 3;
    /// @dev storage slot for range shift
    uint256 internal constant DEX_LITE_RANGE_SHIFT_SLOT = 4;
    /// @dev storage slot for threshold shift
    uint256 internal constant DEX_LITE_THRESHOLD_SHIFT_SLOT = 5;

    // --------------------------------
    // @dev stacked uint256 storage slots bits position data for each:

    // DexVariables
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_FEE = 0;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_REVENUE_CUT = 13;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS = 20;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_SHIFT_ACTIVE = 22;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE = 23;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_CONTRACT_ADDRESS = 63;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_RANGE_PERCENT_SHIFT_ACTIVE = 82;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_UPPER_PERCENT = 83;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_LOWER_PERCENT = 97;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_THRESHOLD_PERCENT_SHIFT_ACTIVE = 111;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_UPPER_SHIFT_THRESHOLD_PERCENT = 112;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_LOWER_SHIFT_THRESHOLD_PERCENT = 119;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_DECIMALS = 126;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_DECIMALS = 131;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_TOTAL_SUPPLY_ADJUSTED = 136;
    uint256 internal constant BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_TOTAL_SUPPLY_ADJUSTED = 196;

    // CenterPriceShift
    uint256 internal constant BITS_DEX_LITE_CENTER_PRICE_SHIFT_LAST_INTERACTION_TIMESTAMP = 0;
    uint256 internal constant BITS_DEX_LITE_CENTER_PRICE_SHIFT_SHIFTING_TIME = 33;
    uint256 internal constant BITS_DEX_LITE_CENTER_PRICE_SHIFT_MAX_CENTER_PRICE = 57;
    uint256 internal constant BITS_DEX_LITE_CENTER_PRICE_SHIFT_MIN_CENTER_PRICE = 85;
    uint256 internal constant BITS_DEX_LITE_CENTER_PRICE_SHIFT_PERCENT = 113;
    uint256 internal constant BITS_DEX_LITE_CENTER_PRICE_SHIFT_TIME_TO_SHIFT = 133;
    uint256 internal constant BITS_DEX_LITE_CENTER_PRICE_SHIFT_TIMESTAMP = 153;

    // RangeShift
    uint256 internal constant BITS_DEX_LITE_RANGE_SHIFT_OLD_UPPER_RANGE_PERCENT = 0;
    uint256 internal constant BITS_DEX_LITE_RANGE_SHIFT_OLD_LOWER_RANGE_PERCENT = 14;
    uint256 internal constant BITS_DEX_LITE_RANGE_SHIFT_TIME_TO_SHIFT = 28;
    uint256 internal constant BITS_DEX_LITE_RANGE_SHIFT_TIMESTAMP = 48;

    // ThresholdShift
    uint256 internal constant BITS_DEX_LITE_THRESHOLD_SHIFT_OLD_UPPER_THRESHOLD_PERCENT = 0;
    uint256 internal constant BITS_DEX_LITE_THRESHOLD_SHIFT_OLD_LOWER_THRESHOLD_PERCENT = 7;
    uint256 internal constant BITS_DEX_LITE_THRESHOLD_SHIFT_TIME_TO_SHIFT = 14;
    uint256 internal constant BITS_DEX_LITE_THRESHOLD_SHIFT_TIMESTAMP = 34;

    // --------------------------------
    // @dev stacked uint256 swapData for LogSwap event
    uint256 internal constant BITS_DEX_LITE_SWAP_DATA_DEX_ID = 0;
    uint256 internal constant BITS_DEX_LITE_SWAP_DATA_SWAP_0_TO_1 = 64;
    uint256 internal constant BITS_DEX_LITE_SWAP_DATA_AMOUNT_IN = 65;
    uint256 internal constant BITS_DEX_LITE_SWAP_DATA_AMOUNT_OUT = 125;

    /// @notice Calculating the slot ID for Dex contract for single mapping at `slot_` for `key_`
    function calculateMappingStorageSlot(uint256 slot_, bytes32 key_) internal pure returns (bytes32) {
        return keccak256(abi.encode(key_, slot_));
    }
}

File 6 of 22 : errorTypes.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.21 <=0.8.29;

library LibsErrorTypes {
    /***********************************|
    |         LiquidityCalcs            | 
    |__________________________________*/

    /// @notice thrown when supply or borrow exchange price is zero at calc token data (token not configured yet)
    uint256 internal constant LiquidityCalcs__ExchangePriceZero = 70001;

    /// @notice thrown when rate data is set to a version that is not implemented
    uint256 internal constant LiquidityCalcs__UnsupportedRateVersion = 70002;

    /// @notice thrown when the calculated borrow rate turns negative. This should never happen.
    uint256 internal constant LiquidityCalcs__BorrowRateNegative = 70003;

    /***********************************|
    |           SafeTransfer            | 
    |__________________________________*/

    /// @notice thrown when safe transfer from for an ERC20 fails
    uint256 internal constant SafeTransfer__TransferFromFailed = 71001;

    /// @notice thrown when safe transfer for an ERC20 fails
    uint256 internal constant SafeTransfer__TransferFailed = 71002;

    /***********************************|
    |           SafeApprove             | 
    |__________________________________*/

    /// @notice thrown when safe approve from for an ERC20 fails
    uint256 internal constant SafeApprove__ApproveFailed = 81001;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

library ReentrancyLock {
    // bytes32(uint256(keccak256("FLUID_REENTRANCY_LOCK")) - 1)
    bytes32 constant REENTRANCY_LOCK_SLOT = 0xb9cde754d19acfff2b3ccabc66f256d3563a0bc5805da4205f01a9bda38a2df7;

    function lock() internal {
        assembly {
            if tload(REENTRANCY_LOCK_SLOT) { revert(0, 0) }
            tstore(REENTRANCY_LOCK_SLOT, 1)
        }
    }

    function unlock() internal {
        assembly { tstore(REENTRANCY_LOCK_SLOT, 0) }
    }
}

// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.21 <=0.8.29;

import { LibsErrorTypes as ErrorTypes } from "./errorTypes.sol";

/// @notice provides minimalistic methods for safe transfers, e.g. ERC20 safeTransferFrom
library SafeTransfer {
    uint256 internal constant MAX_NATIVE_TRANSFER_GAS = 20000; // pass max. 20k gas for native transfers

    error FluidSafeTransferError(uint256 errorId_);

    /// @dev Transfer `amount_` of `token_` from `from_` to `to_`, spending the approval given by `from_` to the
    /// calling contract. If `token_` returns no value, non-reverting calls are assumed to be successful.
    /// Minimally modified from Solmate SafeTransferLib (address as input param for token, Custom Error):
    /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L31-L63
    function safeTransferFrom(address token_, address from_, address to_, uint256 amount_) internal {
        bool success_;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from_" argument.
            mstore(add(freeMemoryPointer, 36), and(to_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to_" argument.
            mstore(add(freeMemoryPointer, 68), amount_) // Append the "amount_" argument. Masking not required as it's a full 32 byte type.

            success_ := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token_, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        if (!success_) {
            revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFromFailed);
        }
    }

    /// @dev Transfer `amount_` of `token_` to `to_`.
    /// If `token_` returns no value, non-reverting calls are assumed to be successful.
    /// Minimally modified from Solmate SafeTransferLib (address as input param for token, Custom Error):
    /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L65-L95
    function safeTransfer(address token_, address to_, uint256 amount_) internal {
        bool success_;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to_, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to_" argument.
            mstore(add(freeMemoryPointer, 36), amount_) // Append the "amount_" argument. Masking not required as it's a full 32 byte type.

            success_ := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token_, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        if (!success_) {
            revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFailed);
        }
    }

    /// @dev Transfer `amount_` of ` native token to `to_`.
    /// Minimally modified from Solmate SafeTransferLib (Custom Error):
    /// https://github.com/transmissions11/solmate/blob/50e15bb566f98b7174da9b0066126a4c3e75e0fd/src/utils/SafeTransferLib.sol#L15-L25
    function safeTransferNative(address to_, uint256 amount_) internal {
        bool success_;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not. Pass limited gas
            success_ := call(MAX_NATIVE_TRANSFER_GAS, to_, amount_, 0, 0, 0, 0)
        }

        if (!success_) {
            revert FluidSafeTransferError(ErrorTypes.SafeTransfer__TransferFailed);
        }
    }
}

File 9 of 22 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.21 <=0.8.29;

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

    struct AddressUint256 {
        address addr;
        uint256 value;
    }

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

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

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

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

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

//SPDX-License-Identifier: MIT
pragma solidity >=0.8.21 <=0.8.29;

import { IProxy } from "../../infiniteProxy/interfaces/iProxy.sol";
import { Structs as AdminModuleStructs } from "../adminModule/structs.sol";

interface IFluidLiquidityAdmin {
    /// @notice adds/removes auths. Auths generally could be contracts which can have restricted actions defined on contract.
    ///         auths can be helpful in reducing governance overhead where it's not needed.
    /// @param authsStatus_ array of structs setting allowed status for an address.
    ///                     status true => add auth, false => remove auth
    function updateAuths(AdminModuleStructs.AddressBool[] calldata authsStatus_) external;

    /// @notice adds/removes guardians. Only callable by Governance.
    /// @param guardiansStatus_ array of structs setting allowed status for an address.
    ///                         status true => add guardian, false => remove guardian
    function updateGuardians(AdminModuleStructs.AddressBool[] calldata guardiansStatus_) external;

    /// @notice changes the revenue collector address (contract that is sent revenue). Only callable by Governance.
    /// @param revenueCollector_  new revenue collector address
    function updateRevenueCollector(address revenueCollector_) external;

    /// @notice changes current status, e.g. for pausing or unpausing all user operations. Only callable by Auths.
    /// @param newStatus_ new status
    ///        status = 2 -> pause, status = 1 -> resume.
    function changeStatus(uint256 newStatus_) external;

    /// @notice                  update tokens rate data version 1. Only callable by Auths.
    /// @param tokensRateData_   array of RateDataV1Params with rate data to set for each token
    function updateRateDataV1s(AdminModuleStructs.RateDataV1Params[] calldata tokensRateData_) external;

    /// @notice                  update tokens rate data version 2. Only callable by Auths.
    /// @param tokensRateData_   array of RateDataV2Params with rate data to set for each token
    function updateRateDataV2s(AdminModuleStructs.RateDataV2Params[] calldata tokensRateData_) external;

    /// @notice updates token configs: fee charge on borrowers interest & storage update utilization threshold.
    ///         Only callable by Auths.
    /// @param tokenConfigs_ contains token address, fee & utilization threshold
    function updateTokenConfigs(AdminModuleStructs.TokenConfig[] calldata tokenConfigs_) external;

    /// @notice updates user classes: 0 is for new protocols, 1 is for established protocols.
    ///         Only callable by Auths.
    /// @param userClasses_ struct array of uint256 value to assign for each user address
    function updateUserClasses(AdminModuleStructs.AddressUint256[] calldata userClasses_) external;

    /// @notice sets user supply configs per token basis. Eg: with interest or interest-free and automated limits.
    ///         Only callable by Auths.
    /// @param userSupplyConfigs_ struct array containing user supply config, see `UserSupplyConfig` struct for more info
    function updateUserSupplyConfigs(AdminModuleStructs.UserSupplyConfig[] memory userSupplyConfigs_) external;

    /// @notice sets a new withdrawal limit as the current limit for a certain user
    /// @param user_ user address for which to update the withdrawal limit
    /// @param token_ token address for which to update the withdrawal limit
    /// @param newLimit_ new limit until which user supply can decrease to.
    ///                  Important: input in raw. Must account for exchange price in input param calculation.
    ///                  Note any limit that is < max expansion or > current user supply will set max expansion limit or
    ///                  current user supply as limit respectively.
    ///                  - set 0 to make maximum possible withdrawable: instant full expansion, and if that goes
    ///                  below base limit then fully down to 0.
    ///                  - set type(uint256).max to make current withdrawable 0 (sets current user supply as limit).
    function updateUserWithdrawalLimit(address user_, address token_, uint256 newLimit_) external;

    /// @notice setting user borrow configs per token basis. Eg: with interest or interest-free and automated limits.
    ///         Only callable by Auths.
    /// @param userBorrowConfigs_ struct array containing user borrow config, see `UserBorrowConfig` struct for more info
    function updateUserBorrowConfigs(AdminModuleStructs.UserBorrowConfig[] memory userBorrowConfigs_) external;

    /// @notice pause operations for a particular user in class 0 (class 1 users can't be paused by guardians).
    /// Only callable by Guardians.
    /// @param user_          address of user to pause operations for
    /// @param supplyTokens_  token addresses to pause withdrawals for
    /// @param borrowTokens_  token addresses to pause borrowings for
    function pauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external;

    /// @notice unpause operations for a particular user in class 0 (class 1 users can't be paused by guardians).
    /// Only callable by Guardians.
    /// @param user_          address of user to unpause operations for
    /// @param supplyTokens_  token addresses to unpause withdrawals for
    /// @param borrowTokens_  token addresses to unpause borrowings for
    function unpauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external;

    /// @notice         collects revenue for tokens to configured revenueCollector address.
    /// @param tokens_  array of tokens to collect revenue for
    /// @dev            Note that this can revert if token balance is < revenueAmount (utilization > 100%)
    function collectRevenue(address[] calldata tokens_) external;

    /// @notice gets the current updated exchange prices for n tokens and updates all prices, rates related data in storage.
    /// @param tokens_ tokens to update exchange prices for
    /// @return supplyExchangePrices_ new supply rates of overall system for each token
    /// @return borrowExchangePrices_ new borrow rates of overall system for each token
    function updateExchangePrices(
        address[] calldata tokens_
    ) external returns (uint256[] memory supplyExchangePrices_, uint256[] memory borrowExchangePrices_);
}

interface IFluidLiquidityLogic is IFluidLiquidityAdmin {
    /// @notice Single function which handles supply, withdraw, borrow & payback
    /// @param token_ address of token (0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native)
    /// @param supplyAmount_ if +ve then supply, if -ve then withdraw, if 0 then nothing
    /// @param borrowAmount_ if +ve then borrow, if -ve then payback, if 0 then nothing
    /// @param withdrawTo_ if withdrawal then to which address
    /// @param borrowTo_ if borrow then to which address
    /// @param callbackData_ callback data passed to `liquidityCallback` method of protocol
    /// @return memVar3_ updated supplyExchangePrice
    /// @return memVar4_ updated borrowExchangePrice
    /// @dev to trigger skipping in / out transfers (gas optimization):
    /// -  ` callbackData_` MUST be encoded so that "from" address is the last 20 bytes in the last 32 bytes slot,
    ///     also for native token operations where liquidityCallback is not triggered!
    ///     from address must come at last position if there is more data. I.e. encode like:
    ///     abi.encode(otherVar1, otherVar2, FROM_ADDRESS). Note dynamic types used with abi.encode come at the end
    ///     so if dynamic types are needed, you must use abi.encodePacked to ensure the from address is at the end.
    /// -   this "from" address must match withdrawTo_ or borrowTo_ and must be == `msg.sender`
    /// -   `callbackData_` must in addition to the from address as described above include bytes32 SKIP_TRANSFERS
    ///     in the slot before (bytes 32 to 63)
    /// -   `msg.value` must be 0.
    /// -   Amounts must be either:
    ///     -  supply(+) == borrow(+), withdraw(-) == payback(-).
    ///     -  Liquidity must be on the winning side (deposit < borrow OR payback < withdraw).
    function operate(
        address token_,
        int256 supplyAmount_,
        int256 borrowAmount_,
        address withdrawTo_,
        address borrowTo_,
        bytes calldata callbackData_
    ) external payable returns (uint256 memVar3_, uint256 memVar4_);
}

interface IFluidLiquidity is IProxy, IFluidLiquidityLogic {}

File 11 of 22 : coreInternals.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

import "./helpers.sol";

abstract contract CoreInternals is Helpers {
    function _swapIn(
        DexKey calldata dexKey_,
        bool swap0To1_,
        uint256 amountIn_
    ) internal returns (uint256 amountOut_) {
        bytes8 dexId_ = bytes8(keccak256(abi.encode(dexKey_)));
        uint256 dexVariables_ = _dexVariables[dexId_];

        if (dexVariables_ == 0) {
            revert DexNotInitialized(dexId_);
        }

        uint256 token0AdjustedSupply_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_TOTAL_SUPPLY_ADJUSTED) & X60;
        uint256 token1AdjustedSupply_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_TOTAL_SUPPLY_ADJUSTED) & X60;
        (uint256 centerPrice_, uint256 token0ImaginaryReserves_, uint256 token1ImaginaryReserves_) = 
            _getPricesAndReserves(dexKey_, dexVariables_, dexId_, token0AdjustedSupply_, token1AdjustedSupply_);

        unchecked {
            if (swap0To1_) {
                uint256 token0Decimals_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_DECIMALS) & X5;
                if (token0Decimals_ > TOKENS_DECIMALS_PRECISION) {
                    amountIn_ /= _tenPow(token0Decimals_ - TOKENS_DECIMALS_PRECISION);
                } else {
                    amountIn_ *= _tenPow(TOKENS_DECIMALS_PRECISION - token0Decimals_);
                }

                if (amountIn_ < FOUR_DECIMALS || amountIn_ > X60) {
                    revert InvalidSwapAmounts(amountIn_);
                }
                if (amountIn_ > (token0ImaginaryReserves_ / 2)) {
                    revert ExcessiveSwapAmount(amountIn_, token0ImaginaryReserves_);
                }

                uint256 fee_ = (amountIn_ * ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_FEE) & X13)) / SIX_DECIMALS;
                // amountOut = (amountIn * iReserveOut) / (iReserveIn + amountIn)
                amountOut_ = ((amountIn_ - fee_) * token1ImaginaryReserves_) / (token0ImaginaryReserves_ + (amountIn_ - fee_));
                token0AdjustedSupply_ += amountIn_ - ((fee_ * ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_REVENUE_CUT) & X7)) / TWO_DECIMALS);

                if (token1AdjustedSupply_ < amountOut_) {
                    revert TokenReservesTooLow(amountOut_, token1AdjustedSupply_);
                }
                token1AdjustedSupply_ -= amountOut_;

                if (((token1AdjustedSupply_) < ((token0AdjustedSupply_ * centerPrice_) / (PRICE_PRECISION * MINIMUM_LIQUIDITY_SWAP)))) {
                    revert TokenReservesRatioTooHigh(token0AdjustedSupply_, token1AdjustedSupply_);
                }
            } else {
                uint256 token1Decimals_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_DECIMALS) & X5;
                if (token1Decimals_ > TOKENS_DECIMALS_PRECISION) {
                    amountIn_ /= _tenPow(token1Decimals_ - TOKENS_DECIMALS_PRECISION);
                } else {
                    amountIn_ *= _tenPow(TOKENS_DECIMALS_PRECISION - token1Decimals_);
                }

                if (amountIn_ < FOUR_DECIMALS || amountIn_ > X60) {
                    revert InvalidSwapAmounts(amountIn_);
                }
                if (amountIn_ > (token1ImaginaryReserves_ / 2)) {
                    revert ExcessiveSwapAmount(amountIn_, token1ImaginaryReserves_);
                }

                uint256 fee_ = (amountIn_ * ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_FEE) & X13)) / SIX_DECIMALS;
                // amountOut = (amountIn * iReserveOut) / (iReserveIn + amountIn)
                amountOut_ = ((amountIn_ - fee_) * token0ImaginaryReserves_) / (token1ImaginaryReserves_ + (amountIn_ - fee_));
                token1AdjustedSupply_ += amountIn_ - ((fee_ * ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_REVENUE_CUT) & X7)) / TWO_DECIMALS);

                if (token0AdjustedSupply_ < amountOut_) {
                    revert TokenReservesTooLow(amountOut_, token0AdjustedSupply_);
                }
                token0AdjustedSupply_ -= amountOut_;

                if (((token0AdjustedSupply_) < ((token1AdjustedSupply_ * PRICE_PRECISION) / (centerPrice_ * MINIMUM_LIQUIDITY_SWAP)))) {
                    revert TokenReservesRatioTooHigh(token0AdjustedSupply_, token1AdjustedSupply_);
                }
            }
        }

        {
            uint256 rebalancingStatus_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS) & X2;
            if (rebalancingStatus_ > 0) {
                // rebalancing is active
                uint256 price_;
                unchecked {
                    price_ = (swap0To1_ ? (token1ImaginaryReserves_ - amountOut_) * PRICE_PRECISION / (token0ImaginaryReserves_ + amountIn_) : 
                        (token1ImaginaryReserves_ + amountIn_) * PRICE_PRECISION / (token0ImaginaryReserves_ - amountOut_));
                }
                rebalancingStatus_ = _getRebalancingStatus(dexVariables_, dexId_, rebalancingStatus_, price_, centerPrice_);
            }
            // NOTE: we are using dexVariables_ and not _dexVariables[dexId_] here to check if the center price shift is active
            // _dexVariables[dexId_] might have become inactive in this transaction above, but still we are storing the timestamp for this transaction
            // storing the timestamp is not important, but we are still doing it because we don't want to use _dexVariables[dexId_] here because of gas
            if (rebalancingStatus_ > 1 || ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_SHIFT_ACTIVE) & X1) == 1) {
                _centerPriceShift[dexId_] = _centerPriceShift[dexId_] & ~(X33 << DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_LAST_INTERACTION_TIMESTAMP) | 
                    (block.timestamp << DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_LAST_INTERACTION_TIMESTAMP);
            }
        }

        if (token0AdjustedSupply_ > X60 || token1AdjustedSupply_ > X60) {
            revert AdjustedSupplyOverflow(dexId_, token0AdjustedSupply_, token1AdjustedSupply_);
        }

        dexVariables_ = _dexVariables[dexId_] & ~(X120 << DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_TOTAL_SUPPLY_ADJUSTED) | 
            (token0AdjustedSupply_ << DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_TOTAL_SUPPLY_ADJUSTED) | 
            (token1AdjustedSupply_ << DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_TOTAL_SUPPLY_ADJUSTED);

        _dexVariables[dexId_] = dexVariables_;

        if (swap0To1_) {
            emit LogSwap(
                (uint256(uint64(dexId_)) << DSL.BITS_DEX_LITE_SWAP_DATA_DEX_ID) | 
                (uint256(1) << DSL.BITS_DEX_LITE_SWAP_DATA_SWAP_0_TO_1) | // swap 0 to 1 bit is 1
                (amountIn_ << DSL.BITS_DEX_LITE_SWAP_DATA_AMOUNT_IN) | 
                (amountOut_ << DSL.BITS_DEX_LITE_SWAP_DATA_AMOUNT_OUT), 
                dexVariables_
            );

            uint256 token1Decimals_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_DECIMALS) & X5;
            if (token1Decimals_ > TOKENS_DECIMALS_PRECISION) {
                amountOut_ *= _tenPow(token1Decimals_ - TOKENS_DECIMALS_PRECISION);
            } else {
                amountOut_ /= _tenPow(TOKENS_DECIMALS_PRECISION - token1Decimals_);
            }

        } else {
            emit LogSwap(
                (uint256(uint64(dexId_)) << DSL.BITS_DEX_LITE_SWAP_DATA_DEX_ID) | 
                // swap 0 to 1 bit is 0
                (amountIn_ << DSL.BITS_DEX_LITE_SWAP_DATA_AMOUNT_IN) | 
                (amountOut_ << DSL.BITS_DEX_LITE_SWAP_DATA_AMOUNT_OUT), 
                dexVariables_
            );

            uint256 token0Decimals_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_DECIMALS) & X5;
            if (token0Decimals_ > TOKENS_DECIMALS_PRECISION) {
                amountOut_ *= _tenPow(token0Decimals_ - TOKENS_DECIMALS_PRECISION);
            } else {
                amountOut_ /= _tenPow(TOKENS_DECIMALS_PRECISION - token0Decimals_);
            }
        }
    }

    function _swapOut(
        DexKey calldata dexKey_,
        bool swap0To1_,
        uint256 amountOut_
    ) internal returns (uint256 amountIn_) {
        bytes8 dexId_ = bytes8(keccak256(abi.encode(dexKey_)));
        uint256 dexVariables_ = _dexVariables[dexId_];

        if (dexVariables_ == 0) {
            revert DexNotInitialized(dexId_);
        }
    
        uint256 token0AdjustedSupply_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_TOTAL_SUPPLY_ADJUSTED) & X60;
        uint256 token1AdjustedSupply_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_TOTAL_SUPPLY_ADJUSTED) & X60;
        (uint256 centerPrice_, uint256 token0ImaginaryReserves_, uint256 token1ImaginaryReserves_) = 
            _getPricesAndReserves(dexKey_, dexVariables_, dexId_, token0AdjustedSupply_, token1AdjustedSupply_);

        unchecked {
            if (swap0To1_) {
                uint256 token1Decimals_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_DECIMALS) & X5;
                if (token1Decimals_ > TOKENS_DECIMALS_PRECISION) {
                    amountOut_ /= _tenPow(token1Decimals_ - TOKENS_DECIMALS_PRECISION);
                } else {
                    amountOut_ *= _tenPow(TOKENS_DECIMALS_PRECISION - token1Decimals_);
                }

                if (amountOut_ < FOUR_DECIMALS || amountOut_ > X60) {
                    revert InvalidSwapAmounts(amountOut_);
                }
                if (amountOut_ > (token1ImaginaryReserves_ / 2)) {
                    revert ExcessiveSwapAmount(amountOut_, token1ImaginaryReserves_);
                }

                // amountIn = (amountOut * iReserveIn) / (iReserveOut - amountOut)
                amountIn_ = (amountOut_ * token0ImaginaryReserves_) / (token1ImaginaryReserves_ - amountOut_);
                uint256 fee_ = ((amountIn_ * SIX_DECIMALS) / (SIX_DECIMALS - ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_FEE) & X13))) - amountIn_;
                amountIn_ += fee_;
                token0AdjustedSupply_ += amountIn_ - ((fee_ * ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_REVENUE_CUT) & X7)) / TWO_DECIMALS);

                if (token1AdjustedSupply_ < amountOut_) {
                    revert TokenReservesTooLow(amountOut_, token1AdjustedSupply_);
                }
                token1AdjustedSupply_ -= amountOut_;

                if (((token1AdjustedSupply_) < ((token0AdjustedSupply_ * centerPrice_) / (PRICE_PRECISION * MINIMUM_LIQUIDITY_SWAP)))) {
                    revert TokenReservesRatioTooHigh(token0AdjustedSupply_, token1AdjustedSupply_);
                }
            } else {
                uint256 token0Decimals_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_DECIMALS) & X5;
                if (token0Decimals_ > TOKENS_DECIMALS_PRECISION) {
                    amountOut_ /= _tenPow(token0Decimals_ - TOKENS_DECIMALS_PRECISION);
                } else {
                    amountOut_ *= _tenPow(TOKENS_DECIMALS_PRECISION - token0Decimals_);
                }
                
                if (amountOut_ < FOUR_DECIMALS || amountOut_ > X60) {
                    revert InvalidSwapAmounts(amountOut_);
                }
                if (amountOut_ > (token0ImaginaryReserves_ / 2)) {
                    revert ExcessiveSwapAmount(amountOut_, token0ImaginaryReserves_);
                }

                // amountIn = (amountOut * iReserveIn) / (iReserveOut - amountOut)
                amountIn_ = (amountOut_ * token1ImaginaryReserves_) / (token0ImaginaryReserves_ - amountOut_);
                uint256 fee_ = ((amountIn_ * SIX_DECIMALS) / (SIX_DECIMALS - ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_FEE) & X13))) - amountIn_;
                amountIn_ += fee_;
                token1AdjustedSupply_ += amountIn_ - ((fee_ * ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_REVENUE_CUT) & X7)) / TWO_DECIMALS);

                if (token0AdjustedSupply_ < amountOut_) {
                    revert TokenReservesTooLow(amountOut_, token0AdjustedSupply_);
                }
                token0AdjustedSupply_ -= amountOut_;

                if (((token0AdjustedSupply_) < ((token1AdjustedSupply_ * PRICE_PRECISION) / (centerPrice_ * MINIMUM_LIQUIDITY_SWAP)))) {
                    revert TokenReservesRatioTooHigh(token0AdjustedSupply_, token1AdjustedSupply_);
                }
            }
        }

        {
            uint256 rebalancingStatus_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS) & X2;
            if (rebalancingStatus_ > 0) {
                // rebalancing is active
                uint256 price_;
                unchecked {
                    price_ = (swap0To1_ ? (token1ImaginaryReserves_ - amountOut_) * PRICE_PRECISION / (token0ImaginaryReserves_ + amountIn_) : 
                        (token1ImaginaryReserves_ + amountIn_) * PRICE_PRECISION / (token0ImaginaryReserves_ - amountOut_));
                }
                rebalancingStatus_ = _getRebalancingStatus(dexVariables_, dexId_, rebalancingStatus_, price_, centerPrice_);
            }
            if (rebalancingStatus_ > 1 || ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_SHIFT_ACTIVE) & X1) == 1) {
                _centerPriceShift[dexId_] = _centerPriceShift[dexId_] & ~(X33 << DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_LAST_INTERACTION_TIMESTAMP) | 
                    (block.timestamp << DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_LAST_INTERACTION_TIMESTAMP);
            }
        }

        if (token0AdjustedSupply_ > X60 || token1AdjustedSupply_ > X60) {
            revert AdjustedSupplyOverflow(dexId_, token0AdjustedSupply_, token1AdjustedSupply_);
        }

        dexVariables_ = _dexVariables[dexId_] & ~(X120 << DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_TOTAL_SUPPLY_ADJUSTED) | 
            (token0AdjustedSupply_ << DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_TOTAL_SUPPLY_ADJUSTED) | 
            (token1AdjustedSupply_ << DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_TOTAL_SUPPLY_ADJUSTED);

        _dexVariables[dexId_] = dexVariables_;

        if (swap0To1_) {
            emit LogSwap(
                (uint256(uint64(dexId_)) << DSL.BITS_DEX_LITE_SWAP_DATA_DEX_ID) | 
                (uint256(1) << DSL.BITS_DEX_LITE_SWAP_DATA_SWAP_0_TO_1) | // swap 0 to 1 bit is 1
                (amountIn_ << DSL.BITS_DEX_LITE_SWAP_DATA_AMOUNT_IN) | 
                (amountOut_ << DSL.BITS_DEX_LITE_SWAP_DATA_AMOUNT_OUT), 
                dexVariables_
            );

            uint256 token0Decimals_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_0_DECIMALS) & X5;
            if (token0Decimals_ > TOKENS_DECIMALS_PRECISION) {
                amountIn_ *= _tenPow(token0Decimals_ - TOKENS_DECIMALS_PRECISION);
            } else {
                amountIn_ /= _tenPow(TOKENS_DECIMALS_PRECISION - token0Decimals_);
            }
        } else {
            emit LogSwap(
                (uint256(uint64(dexId_)) << DSL.BITS_DEX_LITE_SWAP_DATA_DEX_ID) | 
                // swap 0 to 1 bit is 0
                (amountIn_ << DSL.BITS_DEX_LITE_SWAP_DATA_AMOUNT_IN) | 
                (amountOut_ << DSL.BITS_DEX_LITE_SWAP_DATA_AMOUNT_OUT), 
                dexVariables_
            );

            uint256 token1Decimals_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_TOKEN_1_DECIMALS) & X5;
            if (token1Decimals_ > TOKENS_DECIMALS_PRECISION) {
                amountIn_ *= _tenPow(token1Decimals_ - TOKENS_DECIMALS_PRECISION);
            } else {
                amountIn_ /= _tenPow(TOKENS_DECIMALS_PRECISION - token1Decimals_);
            }
        }
    }
}

File 12 of 22 : errors.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;
import "../other/commonImport.sol";

// --- Custom Errors ---
error EstimateSwap(uint256 amountUnspecified);
error AmountLimitExceeded(uint256 amountUnspecified, uint256 amountLimit);
error AmountLimitNotMet(uint256 amountUnspecified, uint256 amountLimit);
error EmptyDexKeysArray();
error InvalidPathLength(uint256 pathLength, uint256 dexKeysLength);
error InvalidAmountLimitsLength(uint256 dexKeysLength, uint256 amountLimitsLength);
error InvalidPathTokenOrder();
error UnauthorizedCaller(address caller);
error DexNotInitialized(bytes32 dexId);
error AdjustedSupplyOverflow(bytes32 dexId, uint256 token0AdjustedSupply, uint256 token1AdjustedSupply);
error ZeroAddress();
error InvalidPower(uint256 power);
error InvalidSwapAmounts(uint256 adjustedAmount);
error ExcessiveSwapAmount(uint256 adjustedAmount, uint256 imaginaryReserve);
error TokenReservesTooLow(uint256 adjustedAmount, uint256 realReserve);
error TokenReservesRatioTooHigh(uint256 token0RealReserve, uint256 token1RealReserve);
error InvalidMsgValue();
error InsufficientNativeTokenReceived(uint256 receivedAmount, uint256 requiredAmount);
error InsufficientERC20Received(uint256 receivedAmount, uint256 requiredAmount);
error DelegateCallFailed();

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;
import "./errors.sol";
import { DexLiteSlotsLink as DSL } from "../../../libraries/dexLiteSlotsLink.sol";
import { FixedPointMathLib } from "solmate/src/utils/FixedPointMathLib.sol";
import { AddressCalcs } from "../../../libraries/addressCalcs.sol";
import { BigMathMinified } from "../../../libraries/bigMathMinified.sol";
import { ReentrancyLock } from "../../../libraries/reentrancyLock.sol";
import { SafeTransfer } from "../../../libraries/safeTransfer.sol";

abstract contract Helpers is CommonImport {
    using BigMathMinified for uint256;

    modifier _reentrancyLock() {
        ReentrancyLock.lock();
        _;
        ReentrancyLock.unlock();
    }

    function _getExtraDataSlot() internal view returns (address extraDataAddress_) {
        assembly {
            extraDataAddress_ := sload(EXTRA_DATA_SLOT)
        }
    }

    function _getGovernanceAddr() internal view returns (address governance_) {
        governance_ = address(uint160(LIQUIDITY.readFromStorage(LIQUIDITY_GOVERNANCE_SLOT)));
    }

    function _callExtraDataSlot(bytes memory data_) internal {
        address extraDataAddress_ = _getExtraDataSlot();
        if (extraDataAddress_ == address(0)) {
            revert ZeroAddress();
        }
        _spell(extraDataAddress_, data_);
    }

    function _tenPow(uint256 power_) internal pure returns (uint256) {
        // keeping the most used powers at the top for better gas optimization
        if (power_ == 3) {
            return 1_000; // used for 6 or 12 decimals (USDC, USDT)
        }
        if (power_ == 9) {
            return 1_000_000_000; // used for 18 decimals (ETH, and many more)
        }
        if (power_ == 1) {
            return 10; // used for 1 decimals (WBTC and more)
        }

        if (power_ == 0) {
            return 1;
        }
        if (power_ == 2) {
            return 100;
        }
        if (power_ == 4) {
            return 10_000;
        }
        if (power_ == 5) {
            return 100_000;
        }
        if (power_ == 6) {
            return 1_000_000;
        }
        if (power_ == 7) {
            return 10_000_000;
        }
        if (power_ == 8) {
            return 100_000_000;
        }

        // We will only need powers from 0 to 9 as token decimals can only be 6 to 18
        revert InvalidPower(power_);
    }

    /// @dev getting reserves outside range.
    /// @param gp_ is geometric mean pricing of upper percent & lower percent
    /// @param pa_ price of upper range or lower range
    /// @param rx_ real reserves of token0 or token1
    /// @param ry_ whatever is rx_ the other will be ry_
    function _calculateReservesOutsideRange(uint256 gp_, uint256 pa_, uint256 rx_, uint256 ry_) internal pure returns (uint256 xa_, uint256 yb_) {
        // equations we have:
        // 1. x*y = k
        // 2. xa*ya = k
        // 3. xb*yb = k
        // 4. Pa = ya / xa = upperRange_ (known)
        // 5. Pb = yb / xb = lowerRange_ (known)
        // 6. x - xa = rx = real reserve of x (known)
        // 7. y - yb = ry = real reserve of y (known)
        // With solving we get:
        // ((Pa*Pb)^(1/2) - Pa)*xa^2 + (rx * (Pa*Pb)^(1/2) + ry)*xa + rx*ry = 0
        // yb = yb = xa * (Pa * Pb)^(1/2)

        // xa = (GP⋅rx + ry + (-rx⋅ry⋅4⋅(GP - Pa) + (GP⋅rx + ry)^2)^0.5) / (2Pa - 2GP)
        // multiply entire equation by 1e27 to remove the price decimals precision of 1e27
        // xa = (GP⋅rx + ry⋅1e27 + (rx⋅ry⋅4⋅(Pa - GP)⋅1e27 + (GP⋅rx + ry⋅1e27)^2)^0.5) / 2*(Pa - GP)
        // dividing the equation with 2*(Pa - GP). Pa is always > GP so answer will be positive.
        // xa = (((GP⋅rx + ry⋅1e27) / 2*(Pa - GP)) + (((rx⋅ry⋅4⋅(Pa - GP)⋅1e27) / 4*(Pa - GP)^2) + ((GP⋅rx + ry⋅1e27) / 2*(Pa - GP))^2)^0.5)
        // xa = (((GP⋅rx + ry⋅1e27) / 2*(Pa - GP)) + (((rx⋅ry⋅1e27) / (Pa - GP)) + ((GP⋅rx + ry⋅1e27) / 2*(Pa - GP))^2)^0.5)

        // dividing in 3 parts for simplification:
        // part1 = (Pa - GP)
        // part2 = (GP⋅rx + ry⋅1e27) / (2*part1)
        // part3 = rx⋅ry
        // note: part1 will almost always be < 1e28 but in case it goes above 1e27 then it's extremely unlikely it'll go above > 1e29
        unchecked {
            uint256 p1_ = pa_ - gp_;
            uint256 p2_ = ((gp_ * rx_) + (ry_ * PRICE_PRECISION)) / (2 * p1_);

            // removed <1e50 check becuase rx_ * ry_ will never be greater than 1e50
            // Directly used p3_ below instead of using a variable for it
            // uint256 p3_ = (rx_ * ry_ * PRICE_PRECISION) / p1_;

            // xa = part2 + (part3 + (part2 * part2))^(1/2)
            // yb = xa_ * gp_
            xa_ = p2_ + FixedPointMathLib.sqrt((((rx_ * ry_ * PRICE_PRECISION) / p1_) + (p2_ * p2_)));
            yb_ = (xa_ * gp_) / PRICE_PRECISION;
        }
    }
    

    /// @dev This function calculates the new value of a parameter after a shifting process
    /// @param current_ The current value is the final value where the shift ends
    /// @param old_ The old value from where shifting started
    /// @param timePassed_ The time passed since shifting started
    /// @param shiftDuration_ The total duration of the shift when old_ reaches current_
    /// @return The new value of the parameter after the shift
    function _calcShiftingDone(uint256 current_, uint256 old_, uint256 timePassed_, uint256 shiftDuration_) internal pure returns (uint256) {
        unchecked {
            if (current_ > old_) {
                return (old_ + (((current_ - old_) * timePassed_) / shiftDuration_));
            } else {
                return (old_ - (((old_ - current_) * timePassed_) / shiftDuration_));
            }
        }
    }

    /// @dev Calculates the new upper and lower range values during an active range shift
    /// @param upperRange_ The target upper range value
    /// @param lowerRange_ The target lower range value
    /// @notice This function handles the gradual shifting of range values over time
    /// @notice If the shift is complete, it updates the state and clears the shift data
    function _calcRangeShifting(
        uint256 upperRange_,
        uint256 lowerRange_,
        bytes8 dexId_
    ) internal returns (uint256, uint256) {
        uint256 rangeShift_ = _rangeShift[dexId_];
        uint256 shiftDuration_ = (rangeShift_ >> DSL.BITS_DEX_LITE_RANGE_SHIFT_TIME_TO_SHIFT) & X20;
        uint256 startTimeStamp_ = (rangeShift_ >> DSL.BITS_DEX_LITE_RANGE_SHIFT_TIMESTAMP) & X33;

        uint256 timePassed_;
        unchecked {
            if ((startTimeStamp_ + shiftDuration_) < block.timestamp) {
                // shifting fully done
                delete _rangeShift[dexId_];
                // making active shift as 0 because shift is over
                // fetching from storage and storing in storage, aside from admin module dexVariables only updates from this function and _calcThresholdShifting.
                _dexVariables[dexId_] = _dexVariables[dexId_] & ~uint256(1 << DSL.BITS_DEX_LITE_DEX_VARIABLES_RANGE_PERCENT_SHIFT_ACTIVE);
                return (upperRange_, lowerRange_);
            }
            timePassed_ = block.timestamp - startTimeStamp_;
        }
        return (
            _calcShiftingDone(upperRange_, (rangeShift_ >> DSL.BITS_DEX_LITE_RANGE_SHIFT_OLD_UPPER_RANGE_PERCENT) & X14, timePassed_, shiftDuration_),
            _calcShiftingDone(lowerRange_, (rangeShift_ >> DSL.BITS_DEX_LITE_RANGE_SHIFT_OLD_LOWER_RANGE_PERCENT) & X14, timePassed_, shiftDuration_)
        );
    }

    /// @dev Calculates the new upper and lower threshold values during an active threshold shift
    /// @param upperThreshold_ The target upper threshold value
    /// @param lowerThreshold_ The target lower threshold value
    /// @return The updated upper threshold, lower threshold
    /// @notice This function handles the gradual shifting of threshold values over time
    /// @notice If the shift is complete, it updates the state and clears the shift data
    function _calcThresholdShifting(
        uint256 upperThreshold_,
        uint256 lowerThreshold_,
        bytes8 dexId_
    ) internal returns (uint256, uint256) {
        uint256 thresholdShift_ = _thresholdShift[dexId_];
        uint256 shiftDuration_ = (thresholdShift_ >> DSL.BITS_DEX_LITE_THRESHOLD_SHIFT_TIME_TO_SHIFT) & X20;
        uint256 startTimeStamp_ = (thresholdShift_ >> DSL.BITS_DEX_LITE_THRESHOLD_SHIFT_TIMESTAMP) & X33;

        uint256 timePassed_;
        unchecked {
            if ((startTimeStamp_ + shiftDuration_) < block.timestamp) {
                // shifting fully done
                delete _thresholdShift[dexId_];
                // making active shift as 0 because shift is over
                // fetching from storage and storing in storage, aside from admin module dexVariables2 only updates from this function and _calcRangeShifting.
                _dexVariables[dexId_] = _dexVariables[dexId_] & ~uint256(1 << DSL.BITS_DEX_LITE_DEX_VARIABLES_THRESHOLD_PERCENT_SHIFT_ACTIVE);
                return (upperThreshold_, lowerThreshold_);
            }
            timePassed_ = block.timestamp - startTimeStamp_;
        }
        return (
            _calcShiftingDone(upperThreshold_, (thresholdShift_ >> DSL.BITS_DEX_LITE_THRESHOLD_SHIFT_OLD_UPPER_THRESHOLD_PERCENT) & X7, timePassed_, shiftDuration_),
            _calcShiftingDone(lowerThreshold_, (thresholdShift_ >> DSL.BITS_DEX_LITE_THRESHOLD_SHIFT_OLD_LOWER_THRESHOLD_PERCENT) & X7, timePassed_, shiftDuration_)
        );
    }

    /// @dev Calculates the new center price during an active price shift
    /// @param dexVariables_ The current state of dex variables
    /// @return newCenterPrice_ The updated center price
    /// @notice This function gradually shifts the center price towards a new target price over time
    /// @notice It uses an external price source (via ICenterPrice) to determine the target price
    /// @notice The shift continues until the current price reaches the target, or the shift duration ends
    /// @notice Once the shift is complete, it updates the state and clears the shift data
    /// @notice The shift rate is dynamic and depends on:
    /// @notice - Time remaining in the shift duration
    /// @notice - The new center price (fetched externally, which may change)
    /// @notice - The current (old) center price
    /// @notice This results in a fuzzy shifting mechanism where the rate can change as these parameters evolve
    /// @notice The externally fetched new center price is expected to not differ significantly from the last externally fetched center price
    function _calcCenterPrice(
        DexKey calldata dexKey_,
        uint256 dexVariables_,
        bytes8 dexId_
    ) internal returns (uint256 newCenterPrice_) {
        uint256 oldCenterPrice_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE) & X40;
        oldCenterPrice_ = (oldCenterPrice_ >> DEFAULT_EXPONENT_SIZE) << (oldCenterPrice_ & DEFAULT_EXPONENT_MASK);
        uint256 centerPriceShift_ = _centerPriceShift[dexId_];
        uint256 startTimeStamp_ = (centerPriceShift_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_TIMESTAMP) & X33;

        uint256 fromTimeStamp_ = (centerPriceShift_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_LAST_INTERACTION_TIMESTAMP) & X33;
        fromTimeStamp_ = fromTimeStamp_ > startTimeStamp_ ? fromTimeStamp_ : startTimeStamp_;

        newCenterPrice_ = ICenterPrice(
            AddressCalcs.addressCalc(DEPLOYER_CONTRACT, ((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_CONTRACT_ADDRESS) & X19)))
            .centerPrice(dexKey_.token0, dexKey_.token1);
        
        unchecked {
            uint256 priceShift_ = (oldCenterPrice_ * ((centerPriceShift_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_PERCENT) & X20) * (block.timestamp - fromTimeStamp_)) 
                                    / (((centerPriceShift_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_TIME_TO_SHIFT) & X20) * SIX_DECIMALS);

            if (newCenterPrice_ > oldCenterPrice_) {
                // shift on positive side
                oldCenterPrice_ += priceShift_;
                if (newCenterPrice_ > oldCenterPrice_) {
                    newCenterPrice_ = oldCenterPrice_;
                } else {
                    // shifting fully done
                    _centerPriceShift[dexId_] = _centerPriceShift[dexId_] & ~(X73 << DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_PERCENT);
                    // making active shift as 0 because shift is over
                    // fetching from storage and storing in storage, aside from admin module dexVariables2 only updates these shift function.
                    _dexVariables[dexId_] = _dexVariables[dexId_] & ~uint256(1 << DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_SHIFT_ACTIVE);
                }
            } else {
                oldCenterPrice_ = oldCenterPrice_ > priceShift_ ? oldCenterPrice_ - priceShift_ : 0;
                // In case of oldCenterPrice_ ending up 0, which could happen when a lot of time has passed (pool has no swaps for many days or weeks)
                // then below we get into the else logic which will fully conclude shifting and return newCenterPrice_
                // as it was fetched from the external center price source.
                // not ideal that this would ever happen unless the pool is not in use and all/most users have left leaving not enough liquidity to trade on
                if (newCenterPrice_ < oldCenterPrice_) {
                    newCenterPrice_ = oldCenterPrice_;
                } else {
                    // shifting fully done
                    _centerPriceShift[dexId_] = _centerPriceShift[dexId_] & ~(X73 << DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_PERCENT);
                    // making active shift as 0 because shift is over
                    // fetching from storage and storing in storage, aside from admin module dexVariables2 only updates these shift function.
                    _dexVariables[dexId_] = _dexVariables[dexId_] & ~uint256(1 << DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_SHIFT_ACTIVE);
                }
            }
        }
    }

    /// @notice Calculates and returns the current prices and exchange prices for the pool
    /// @param dexVariables_ The first set of DEX variables containing various pool parameters
    function _getPricesAndReserves(
        DexKey calldata dexKey_,
        uint256 dexVariables_,
        bytes8 dexId_,
        uint256 token0Supply_,
        uint256 token1Supply_
    ) internal returns (uint256 centerPrice_, uint256 token0ImaginaryReserves_, uint256 token1ImaginaryReserves_) {
        // Fetch center price
        if (((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_SHIFT_ACTIVE) & X1) == 0) {
            // centerPrice_ => center price nonce
            centerPrice_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE_CONTRACT_ADDRESS) & X19;
            if (centerPrice_ == 0) {
                centerPrice_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_CENTER_PRICE) & X40;
                centerPrice_ = (centerPrice_ >> DEFAULT_EXPONENT_SIZE) << (centerPrice_ & DEFAULT_EXPONENT_MASK);
            } else {
                // center price should be fetched from external source. For exmaple, in case of wstETH <> ETH pool,
                // we would want the center price to be pegged to wstETH exchange rate into ETH
                centerPrice_ = 
                    ICenterPrice(AddressCalcs.addressCalc(DEPLOYER_CONTRACT, centerPrice_)).centerPrice(dexKey_.token0, dexKey_.token1);
            }
        } else {
            // an active centerPrice_ shift is going on
            centerPrice_ = _calcCenterPrice(dexKey_, dexVariables_, dexId_);
        }

        uint256 upperRangePercent_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_UPPER_PERCENT) & X14;
        uint256 lowerRangePercent_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_LOWER_PERCENT) & X14;
        if (((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_RANGE_PERCENT_SHIFT_ACTIVE) & X1) == 1) {
            // an active range shift is going on
            (upperRangePercent_, lowerRangePercent_) = _calcRangeShifting(upperRangePercent_, lowerRangePercent_, dexId_);
        }

        uint256 upperRangePrice_;
        uint256 lowerRangePrice_;
        unchecked {
            // 1% = 1e2, 100% = 1e4
            upperRangePrice_ = (centerPrice_ * FOUR_DECIMALS) / (FOUR_DECIMALS - upperRangePercent_);
            // 1% = 1e2, 100% = 1e4
            lowerRangePrice_ = (centerPrice_ * (FOUR_DECIMALS - lowerRangePercent_)) / FOUR_DECIMALS;
        }

        // Rebalance center price if rebalancing is on
        // temp_ => rebalancingStatus_
        uint256 temp_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS) & X2;
        uint256 temp2_;
        if (temp_ > 1) {
            unchecked {
                // temp2_ => centerPriceShift_
                if (temp_ == 2) {
                    temp2_ = _centerPriceShift[dexId_];
                    uint256 shiftingTime_ = (temp2_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_SHIFTING_TIME) & X24;
                    uint256 timeElapsed_ = block.timestamp - ((temp2_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_LAST_INTERACTION_TIMESTAMP) & X33);
                    // price shifting towards upper range
                    if (timeElapsed_ < shiftingTime_) {
                        centerPrice_ = centerPrice_ + (((upperRangePrice_ - centerPrice_) * timeElapsed_) / shiftingTime_);
                    } else {
                        // 100% price shifted
                        centerPrice_ = upperRangePrice_;
                    }
                } else if (temp_ == 3) {
                    temp2_ = _centerPriceShift[dexId_];
                    uint256 shiftingTime_ = (temp2_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_SHIFTING_TIME) & X24;
                    uint256 timeElapsed_ = block.timestamp - ((temp2_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_LAST_INTERACTION_TIMESTAMP) & X33);
                    // price shifting towards lower range
                    if (timeElapsed_ < shiftingTime_) {
                        centerPrice_ = centerPrice_ - (((centerPrice_ - lowerRangePrice_) * timeElapsed_) / shiftingTime_);
                    } else {
                        // 100% price shifted
                        centerPrice_ = lowerRangePrice_;
                    }
                }

                // If rebalancing actually happened then make sure price is within min and max bounds, and update range prices
                if (temp2_ > 0) {
                    // Make sure center price is within min and max bounds
                    // temp_ => max center price
                    temp_ = (temp2_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_MAX_CENTER_PRICE) & X28;
                    temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);
                    if (centerPrice_ > temp_) {
                        // if center price is greater than max center price
                        centerPrice_ = temp_;
                    } else {
                        // check if center price is less than min center price
                        // temp_ => min center price
                        temp_ = (temp2_ >> DSL.BITS_DEX_LITE_CENTER_PRICE_SHIFT_MIN_CENTER_PRICE) & X28;
                        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);
                        if (centerPrice_ < temp_) centerPrice_ = temp_;
                    }

                    // Update range prices as center price moved
                    upperRangePrice_ = (centerPrice_ * FOUR_DECIMALS) / (FOUR_DECIMALS - upperRangePercent_);
                    lowerRangePrice_ = (centerPrice_ * (FOUR_DECIMALS - lowerRangePercent_)) / FOUR_DECIMALS;
                }
            }  
        }

        // temp_ => geometricMeanPrice_
        unchecked {         
            if (upperRangePrice_ < 1e38) {
                // 1e38 * 1e38 = 1e76 which is less than max uint limit
                temp_ = FixedPointMathLib.sqrt(upperRangePrice_ * lowerRangePrice_);
            } else {
                // upperRange_ price is pretty large hence lowerRange_ will also be pretty large
                temp_ = FixedPointMathLib.sqrt((upperRangePrice_ / 1e18) * (lowerRangePrice_ / 1e18)) * 1e18;
            }
        }

        if (temp_ < 1e27) {
            (token0ImaginaryReserves_, token1ImaginaryReserves_) = 
                _calculateReservesOutsideRange(temp_, upperRangePrice_, token0Supply_, token1Supply_);
        } else {
            // inversing, something like `xy = k` so for calculation we are making everything related to x into y & y into x
            // 1 / geometricMean for new geometricMean
            // 1 / lowerRange will become upper range
            // 1 / upperRange will become lower range
            unchecked {
                (token1ImaginaryReserves_, token0ImaginaryReserves_) = _calculateReservesOutsideRange(
                    (1e54 / temp_),
                    (1e54 / lowerRangePrice_),
                    token1Supply_,
                    token0Supply_
                );
            }
        }

        unchecked {
            token0ImaginaryReserves_ += token0Supply_;
            token1ImaginaryReserves_ += token1Supply_;
        }
    }

    function _getRebalancingStatus(
        uint256 dexVariables_, 
        bytes8 dexId_, 
        uint256 rebalancingStatus_, 
        uint256 price_, 
        uint256 centerPrice_
    ) internal returns (uint256) {
        uint256 upperRange_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_UPPER_PERCENT) & X14;
        uint256 lowerRange_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_LOWER_PERCENT) & X14;

        // NOTE: we are using dexVariables_ and not _dexVariables[dexId_] here to check if the range shift is active
        // range shift might have already ended in this transaction above, but still calling _calcRangeShifting again because we don't want to use _dexVariables[dexId_] here because of gas
        if (((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_RANGE_PERCENT_SHIFT_ACTIVE) & X1) == 1) {
            // an active range shift is going on
            (upperRange_, lowerRange_) = _calcRangeShifting(upperRange_, lowerRange_, dexId_);
        }

        unchecked {
            // adding into unchecked because upperRangePercent_ & lowerRangePercent_ can only be > 0 & < FOUR_DECIMALS
            // 1% = 1e2, 100% = 1e4
            upperRange_ = (centerPrice_ * FOUR_DECIMALS) / (FOUR_DECIMALS - upperRange_);
            // 1% = 1e2, 100% = 1e4
            lowerRange_ = (centerPrice_ * (FOUR_DECIMALS - lowerRange_)) / FOUR_DECIMALS;
        }

        // Calculate threshold prices
        uint256 upperThreshold_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_UPPER_SHIFT_THRESHOLD_PERCENT) & X7;
        uint256 lowerThreshold_ = (dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_LOWER_SHIFT_THRESHOLD_PERCENT) & X7;
        if (((dexVariables_ >> DSL.BITS_DEX_LITE_DEX_VARIABLES_THRESHOLD_PERCENT_SHIFT_ACTIVE) & X1) == 1) {
            // if active shift is going on for threshold then calculate threshold real time
            (upperThreshold_, lowerThreshold_) = _calcThresholdShifting(upperThreshold_, lowerThreshold_, dexId_);
        }

        unchecked {
            upperThreshold_ = 
                (centerPrice_ + ((upperRange_ - centerPrice_) * (TWO_DECIMALS - upperThreshold_)) / TWO_DECIMALS);
            lowerThreshold_ = 
                (centerPrice_ - ((centerPrice_ - lowerRange_) * (TWO_DECIMALS - lowerThreshold_)) / TWO_DECIMALS);
        }

        if (price_ > upperThreshold_) {
            if (rebalancingStatus_ != 2) {
                _dexVariables[dexId_] = _dexVariables[dexId_] & ~(X2 << DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS) | 
                    (2 << DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS);
                return 2;
            }
        } else if (price_ < lowerThreshold_) {
            if (rebalancingStatus_ != 3) {
                _dexVariables[dexId_] = _dexVariables[dexId_] & ~(X2 << DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS) | 
                    (3 << DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS);
                return 3;
            }
        } else {
            if (rebalancingStatus_ != 1) {
                _dexVariables[dexId_] = _dexVariables[dexId_] & ~(X2 << DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS) | 
                    (1 << DSL.BITS_DEX_LITE_DEX_VARIABLES_REBALANCING_STATUS);
                return 1;
            }
        }

        return rebalancingStatus_;
    }

    function _transferTokens(
        address tokenIn_,
        uint256 amountIn_,
        address tokenOut_,
        uint256 amountOut_,
        address to_,
        bool isCallback_,
        bytes calldata callbackData_
    ) internal {
        if (to_ == address(0)) {
            to_ = msg.sender;
        }

        // Transfer tokens out first
        if (tokenOut_ == NATIVE_TOKEN) {
            SafeTransfer.safeTransferNative(to_, amountOut_);
        } else {
            SafeTransfer.safeTransfer(tokenOut_, to_, amountOut_);
        }

        // Transfer tokens in
        if (tokenIn_ == NATIVE_TOKEN) {
            if (isCallback_ && msg.value == 0) {
                uint256 ethBalance_ = address(this).balance;
                IDexLiteCallback(msg.sender).dexCallback(tokenIn_, amountIn_, callbackData_);
                if (address(this).balance - ethBalance_ < amountIn_) revert InsufficientNativeTokenReceived(address(this).balance - ethBalance_, amountIn_);
            }  else {
                if (msg.value < amountIn_) {
                    revert InsufficientNativeTokenReceived(msg.value, amountIn_);
                }
                if (msg.value > amountIn_) {
                    SafeTransfer.safeTransferNative(msg.sender, msg.value - amountIn_);
                }
                // if msg.value == amountIn_ then that means the transfer has already happened
            }
        } else {
            if (msg.value > 0) {
                revert InvalidMsgValue(); // msg.value should be 0 for non native tokens
            }
            if (isCallback_) {
                uint256 tokenInBalance_ = IERC20(tokenIn_).balanceOf(address(this));
                IDexLiteCallback(msg.sender).dexCallback(tokenIn_, amountIn_, callbackData_);
                if ((IERC20(tokenIn_).balanceOf(address(this)) - tokenInBalance_) < amountIn_) {
                    revert InsufficientERC20Received(IERC20(tokenIn_).balanceOf(address(this)) - tokenInBalance_, amountIn_);
                }
            } else {
                SafeTransfer.safeTransferFrom(tokenIn_, msg.sender, address(this), amountIn_);
            }
        }
    }

    /// @dev            do any arbitrary call
    /// @param target_  Address to which the call needs to be delegated
    /// @param data_    Data to execute at the delegated address
    function _spell(address target_, bytes memory data_) internal returns (bytes memory response_) {
        assembly {
            let succeeded := delegatecall(gas(), target_, add(data_, 0x20), mload(data_), 0, 0)
            let size := returndatasize()

            response_ := mload(0x40)
            mstore(0x40, add(response_, and(add(add(size, 0x20), 0x1f), not(0x1f))))
            mstore(response_, size)
            returndatacopy(add(response_, 0x20), 0, size)

            if iszero(succeeded) {
                // throw if delegatecall failed
                returndatacopy(0x00, 0x00, size)
                revert(0x00, size)
            }
        }
    }
}

File 14 of 22 : commonImport.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

import "./variables.sol";

abstract contract CommonImport is Variables {}

File 15 of 22 : constantVariables.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

import "./events.sol";

abstract contract ConstantVariables {
    /*//////////////////////////////////////////////////////////////
                                CONSTANTS
    //////////////////////////////////////////////////////////////*/

    /// bytes32(uint256(keccak256("FLUID_DEX_LITE_EXTRA_DATA")) - 1)
    bytes32 internal constant EXTRA_DATA_SLOT = 0x7e8134afb5ed35d36cb65e24b9a4712a52bb77d952806c1acf50970d2107797f;

    /// This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1
    /// The exact slot which stored the admin address in infinite proxy of liquidity contracts
    bytes32 internal constant LIQUIDITY_GOVERNANCE_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    bool internal constant SWAP_SINGLE = true;
    bool internal constant SWAP_HOP = false;

    address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    uint256 internal constant NATIVE_TOKEN_DECIMALS = 18;
    uint256 internal constant TOKENS_DECIMALS_PRECISION = 9;

    uint8 internal constant MIN_TOKEN_DECIMALS = 6;
    uint8 internal constant MAX_TOKEN_DECIMALS = 18;

    uint256 internal constant SMALL_COEFFICIENT_SIZE = 20;
    uint256 internal constant BIG_COEFFICIENT_SIZE = 32;

    uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;
    uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;

    uint256 internal constant X1 = 0x1;
    uint256 internal constant X2 = 0x3;
    uint256 internal constant X5 = 0x1f;
    uint256 internal constant X7 = 0x7f;
    uint256 internal constant X13 = 0x1fff;
    uint256 internal constant X14 = 0x3fff;
    uint256 internal constant X19 = 0x7ffff;
    uint256 internal constant X20 = 0xfffff;
    uint256 internal constant X24 = 0xffffff;
    uint256 internal constant X28 = 0xfffffff;
    uint256 internal constant X33 = 0x1ffffffff;
    uint256 internal constant X40 = 0xffffffffff;
    uint256 internal constant X56 = 0xffffffffffffff;
    uint256 internal constant X60 = 0xfffffffffffffff;
    uint256 internal constant X73 = 0x1ffffffffffffffffff;
    uint256 internal constant X120 = 0xffffffffffffffffffffffffffffff;
    uint256 internal constant X128 = 0xffffffffffffffffffffffffffffffff;
   
    uint256 internal constant TWO_DECIMALS = 1e2;
    uint256 internal constant FOUR_DECIMALS = 1e4;
    uint256 internal constant SIX_DECIMALS = 1e6;

    uint256 internal constant PRICE_PRECISION = 1e27;

    /// after swap token0 reserves should not be less than token1InToken0 / MINIMUM_LIQUIDITY_SWAP
    /// after swap token1 reserves should not be less than token0InToken1 / MINIMUM_LIQUIDITY_SWAP
    uint256 internal constant MINIMUM_LIQUIDITY_SWAP = 1e4;

    bytes32 internal constant ESTIMATE_SWAP = keccak256(bytes("ESTIMATE_SWAP"));
}

File 16 of 22 : events.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

import "./interfaces.sol";

event LogSwap(uint256 swapData, uint256 dexVariables);
// swapData
// First 64 bits => 0   - 63  => dexId
// Next  1  bit  => 64        => swap 0 to 1 (1 => true, 0 => false)
// Next  60 bits => 65  - 124 => amount in adjusted
// Next  60 bits => 125 - 184 => amount out adjusted

// dexVariables
// Same as variables.sol

File 17 of 22 : immutableVariables.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;
import "./constantVariables.sol";

// TODO
// import { IFluidDexFactory } from "../../interfaces/iDexFactory.sol";
// import { Error } from "../../error.sol";
// import { ErrorTypes } from "../../errorTypes.sol";

abstract contract ImmutableVariables is ConstantVariables {
    /*//////////////////////////////////////////////////////////////
                               IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    /// @dev Address of liquidity contract
    IFluidLiquidity internal immutable LIQUIDITY;

    /// @dev Address of contract used for deploying center price & hook related contract
    address internal immutable DEPLOYER_CONTRACT;
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;
import { IERC20 } from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import { IFluidLiquidity } from "../../../liquidity/interfaces/iLiquidity.sol";
import "./structs.sol";

interface IERC20WithDecimals is IERC20 {
    function decimals() external view returns (uint8);
}

interface IDexLiteCallback {
    function dexCallback(address token_, uint256 amount_, bytes calldata data_) external;
}

interface ICenterPrice {
    /// @notice Retrieves the center price for the pool
    /// @dev This function is marked as non-constant (potentially state-changing) to allow flexibility in price fetching mechanisms.
    ///      While typically used as a read-only operation, this design permits write operations if needed for certain token pairs
    ///      (e.g., fetching up-to-date exchange rates that may require state changes).
    /// @return price The current price of token0 in terms of token1, expressed with 27 decimal places
    function centerPrice(address token0_, address token1_) external returns (uint256);
}

File 19 of 22 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

import "./events.sol";

struct DexKey {
    address token0;
    address token1;
    bytes32 salt;
}

struct TransferParams {
    address to;
    bool isCallback;
    bytes callbackData;
    bytes extraData;
}

File 20 of 22 : variables.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

import "./immutableVariables.sol";

abstract contract Variables is ImmutableVariables {
    /// @dev admin address
    mapping(address => uint256) internal _isAuth;

    /// @dev dexes list
    DexKey[] internal _dexesList;

    // First 13 bits => 0   - 12  => fee (1% = 10000, max value: 8191 = .8191%)
    // Next  7  bits => 13  - 19  => revenue cut (1 = 1%)
    // Next  2  bit  => 20  - 21  => rebalancing status (0 = off, 1 = on but not active, 2 = rebalancing active towards upper range, 3 = rebalancing active towards lower range)
    // Next  1  bit  => 22        => is center price shift active
    // Next  40 bits => 23  - 62  => center price. Center price from where the ranges will be calculated. BigNumber (32 bits precision, 8 bits exponent)
    // Next  19 bits => 63  - 81  => center price contract address (Deployment Factory Nonce)
    // Next  1  bit  => 82        => range percent shift active or not, 0 = false, 1 = true, if true than that means governance has updated the below percents and the update should happen with a specified time
    // Next  14 bits => 83  - 96  => upperPercent (1% = 100) upperRange - upperRange * upperPercent = centerPrice. Hence, upperRange = centerPrice / (1 - upperPercent)
    // Next  14 bits => 97  - 110 => lowerPercent (1% = 100) lowerRange = centerPrice - centerPrice * lowerPercent
    // Next  1  bit  => 111       => threshold percent shift active or not, 0 = false, 1 = true, if true than that means governance has updated the below percents and the update should happen with a specified time
    // Next  7 bits  => 112 - 118 => upper shift threshold percent, 1 = 1%. 100 = 100%. if currentPrice > (centerPrice + (upperRange - centerPrice) * (100 - upperShiftThresholdPercent) / 100) then trigger shift
    // Next  7 bits  => 119 - 125 => lower shift threshold percent, 1 = 1%. 100 = 100%. if currentPrice < (centerPrice - (centerPrice - lowerRange) * (100 - lowerShiftThresholdPercent) / 100) then trigger shift
    // Next  5  bits => 126 - 130 => token 0 decimals
    // Next  5  bits => 131 - 135 => token 1 decimals
    // Next  60 bits => 136 - 195 => total token 0 adjusted amount
    // Next  60 bits => 196 - 255 => total token 1 adjusted amount
    /// @dev dex id => dex variables
    mapping(bytes8 => uint256) internal _dexVariables;

    /// NOTE: Center price shift is always fuzzy, and can shift because of rebalancing or center price shift
    // First 33 bits => 0   - 32  => last interaction timestamp (only stored when either rebalancing or center price shift is active)
    /// REBALANCING RELATED THINGS
    // First 24 bits => 33  - 56  => shifting time (max ~194 days)
    // Next  28 bits => 57  - 84  => max center price. BigNumber (20 bits precision, 8 bits exponent)
    // Next  28 bits => 85  - 112 => min center price. BigNumber (20 bits precision, 8 bits exponent)
    /// CENTER PRICE SHIFT RELATED THINGS
    // First 20 bits => 113 - 132 => % shift (1% = 1000)
    // Next  20 bits => 133 - 152 => time to shift that percent, ~12 days max
    // Next  33 bits => 153 - 185 => timestamp of when the shift started
    // Last 70 bits empty
    /// @dev dex id => center price shift
    mapping(bytes8 => uint256) internal _centerPriceShift;

    /// Range Shift (first 128 bits)
    // First 14 bits => 0  - 13 => old upper range percent
    // Next  14 bits => 14 - 27 => old lower range percent
    // Next  20 bits => 28 - 47 => time to shift in seconds, ~12 days max, shift can last for max ~12 days
    // Next  33 bits => 48 - 80 => timestamp of when the shift has started.
    // Last 175 bits empty
    /// @dev dex id => range shift
    mapping(bytes8 => uint256) internal _rangeShift;

    // First 7  bits => 0  - 6  => old upper threshold percent
    // Next  7  bits => 7  - 13 => old lower threshold percent
    // Next  20 bits => 14 - 33 => time to shift in seconds, ~12 days max, shift can last for max ~12 days
    // Next  33 bits => 34 - 66 => timestamp of when the shift has started
    // Last 189 bits empty
    /// @dev dex id => threshold shift
    mapping(bytes8 => uint256) internal _thresholdShift;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"auth_","type":"address"},{"internalType":"address","name":"liquidity_","type":"address"},{"internalType":"address","name":"deployerContract_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes32","name":"dexId","type":"bytes32"},{"internalType":"uint256","name":"token0AdjustedSupply","type":"uint256"},{"internalType":"uint256","name":"token1AdjustedSupply","type":"uint256"}],"name":"AdjustedSupplyOverflow","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountUnspecified","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"}],"name":"AmountLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountUnspecified","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"}],"name":"AmountLimitNotMet","type":"error"},{"inputs":[{"internalType":"bytes32","name":"dexId","type":"bytes32"}],"name":"DexNotInitialized","type":"error"},{"inputs":[],"name":"EmptyDexKeysArray","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountUnspecified","type":"uint256"}],"name":"EstimateSwap","type":"error"},{"inputs":[{"internalType":"uint256","name":"adjustedAmount","type":"uint256"},{"internalType":"uint256","name":"imaginaryReserve","type":"uint256"}],"name":"ExcessiveSwapAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"errorId_","type":"uint256"}],"name":"FluidSafeTransferError","type":"error"},{"inputs":[{"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"internalType":"uint256","name":"requiredAmount","type":"uint256"}],"name":"InsufficientERC20Received","type":"error"},{"inputs":[{"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"internalType":"uint256","name":"requiredAmount","type":"uint256"}],"name":"InsufficientNativeTokenReceived","type":"error"},{"inputs":[{"internalType":"uint256","name":"dexKeysLength","type":"uint256"},{"internalType":"uint256","name":"amountLimitsLength","type":"uint256"}],"name":"InvalidAmountLimitsLength","type":"error"},{"inputs":[],"name":"InvalidMsgValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"pathLength","type":"uint256"},{"internalType":"uint256","name":"dexKeysLength","type":"uint256"}],"name":"InvalidPathLength","type":"error"},{"inputs":[],"name":"InvalidPathTokenOrder","type":"error"},{"inputs":[{"internalType":"uint256","name":"power","type":"uint256"}],"name":"InvalidPower","type":"error"},{"inputs":[{"internalType":"uint256","name":"adjustedAmount","type":"uint256"}],"name":"InvalidSwapAmounts","type":"error"},{"inputs":[{"internalType":"uint256","name":"token0RealReserve","type":"uint256"},{"internalType":"uint256","name":"token1RealReserve","type":"uint256"}],"name":"TokenReservesRatioTooHigh","type":"error"},{"inputs":[{"internalType":"uint256","name":"adjustedAmount","type":"uint256"},{"internalType":"uint256","name":"realReserve","type":"uint256"}],"name":"TokenReservesTooLow","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"swapData","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dexVariables","type":"uint256"}],"name":"LogSwap","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"bytes32","name":"slot_","type":"bytes32"}],"name":"readFromStorage","outputs":[{"internalType":"uint256","name":"result_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"path_","type":"address[]"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct DexKey[]","name":"dexKeys_","type":"tuple[]"},{"internalType":"int256","name":"amountSpecified_","type":"int256"},{"internalType":"uint256[]","name":"amountLimits_","type":"uint256[]"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"isCallback","type":"bool"},{"internalType":"bytes","name":"callbackData","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct TransferParams","name":"transferParams_","type":"tuple"}],"name":"swapHop","outputs":[{"internalType":"uint256","name":"amountUnspecified_","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct DexKey","name":"dexKey_","type":"tuple"},{"internalType":"bool","name":"swap0To1_","type":"bool"},{"internalType":"int256","name":"amountSpecified_","type":"int256"},{"internalType":"uint256","name":"amountLimit_","type":"uint256"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"bool","name":"isCallback_","type":"bool"},{"internalType":"bytes","name":"callbackData_","type":"bytes"},{"internalType":"bytes","name":"extraData_","type":"bytes"}],"name":"swapSingle","outputs":[{"internalType":"uint256","name":"amountUnspecified_","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c060405234801561000f575f5ffd5b506040516140f83803806140f883398101604081905261002e91610074565b6001600160a01b039283165f908152602081905260409020600190559082166080521660a0526100b4565b80516001600160a01b038116811461006f575f5ffd5b919050565b5f5f5f60608486031215610086575f5ffd5b61008f84610059565b925061009d60208501610059565b91506100ab60408501610059565b90509250925092565b60805160a05161401c6100dc5f395f818161247901526131c601525f6101ee015261401c5ff3fe608060405260043610610037575f3560e01c80637fc9d4ad146100f7578063a3c779fd1461011c578063b5c736e41461012f5761003e565b3661003e57005b5f36606061004a61014d565b335f9081526020819052604090205460011480159061008657503361006d61019e565b73ffffffffffffffffffffffffffffffffffffffff1614155b156100c4576040517fd86ad9cf0000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b5f806100d2848601866137f8565b915091506100e08282610271565b925050506100ec6102b3565b915050805190602001f35b61010a61010536600461395f565b6102d8565b60405190815260200160405180910390f35b61010a61012a366004613a85565b610634565b34801561013a575f5ffd5b5061010a610149366004613b88565b5490565b7fb9cde754d19acfff2b3ccabc66f256d3563a0bc5805da4205f01a9bda38a2df75c15610178575f5ffd5b60017fb9cde754d19acfff2b3ccabc66f256d3563a0bc5805da4205f01a9bda38a2df75d565b6040517fb5c736e40000000000000000000000000000000000000000000000000000000081527fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360048201525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401602060405180830381865afa158015610248573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061026c9190613b9f565b905090565b60605f5f835160208501865af43d6040519250601f19601f6020830101168301604052808352805f602085013e816102ab57805f5f3e805ffd5b505092915050565b5f7fb9cde754d19acfff2b3ccabc66f256d3563a0bc5805da4205f01a9bda38a2df75d565b5f6102e161014d565b5f8913156104a6576102f48b8b8b610ff5565b90508781101561033a576040517f552ac31300000000000000000000000000000000000000000000000000000000815260048101829052602481018990526044016100bb565b5f82900361039c57891561037b5761037661035860208d018d613bb6565b8a8d602001602081019061036c9190613bb6565b848b8b8b8b611794565b61061e565b61037661038e60408d0160208e01613bb6565b8a61036c60208f018f613bb6565b60408051808201909152600d81527f455354494d4154455f53574150000000000000000000000000000000000000006020909101527f9fbe8fb0ae8f68c4e90aaac8dee895c5ba9596470c68a601101c9d65a103a9436103fc8385613bd8565b03610436576040517f5fea03c9000000000000000000000000000000000000000000000000000000008152600481018290526024016100bb565b61037660018c8c8c85888860405160200161045696959493929190613cb2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526104929291602001613ce6565b604051602081830303815290604052611c54565b6104b98b8b6104b48c613d6f565b611cdb565b9050878111156104ff576040517f97121c2100000000000000000000000000000000000000000000000000000000815260048101829052602481018990526044016100bb565b5f8290036105645789156105435761037661051d60208d018d613bb6565b828d60200160208101906105319190613bb6565b61053a8d613d6f565b8b8b8b8b611794565b61037661055660408d0160208e01613bb6565b8261053160208f018f613bb6565b60408051808201909152600d81527f455354494d4154455f53574150000000000000000000000000000000000000006020909101527f9fbe8fb0ae8f68c4e90aaac8dee895c5ba9596470c68a601101c9d65a103a9436105c48385613bd8565b036105fe576040517f5fea03c9000000000000000000000000000000000000000000000000000000008152600481018290526024016100bb565b61061e60018c8c8c85888860405160200161045696959493929190613cb2565b6106266102b3565b9a9950505050505050505050565b5f61063d61014d565b5f869003610677576040517fd15d5eeb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8561068360018a613da5565b146106c4576040517f88b3170e00000000000000000000000000000000000000000000000000000000815260048101899052602481018790526044016100bb565b828614610707576040517fb932f13700000000000000000000000000000000000000000000000000000000815260048101849052602481018790526044016100bb565b5f851315610b865750835f5b86811015610a15575f88888381811061072e5761072e613db8565b6107449260206060909202019081019150613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b8481811061076c5761076c613db8565b90506020020160208101906107819190613bb6565b73ffffffffffffffffffffffffffffffffffffffff1614801561082157508888838181106107b1576107b1613db8565b90506060020160200160208101906107c99190613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b846001018181106107f4576107f4613db8565b90506020020160208101906108099190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16145b1561082e57506001610971565b88888381811061084057610840613db8565b90506060020160200160208101906108589190613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b8481811061088057610880613db8565b90506020020160208101906108959190613bb6565b73ffffffffffffffffffffffffffffffffffffffff1614801561093357508888838181106108c5576108c5613db8565b6108db9260206060909202019081019150613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b8460010181811061090657610906613db8565b905060200201602081019061091b9190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16145b1561093f57505f610971565b6040517f0a33bc9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61099389898481811061098657610986613db8565b9050606002018285610ff5565b92508585838181106109a7576109a7613db8565b90506020020135831015610a0c57828686848181106109c8576109c8613db8565b905060200201356040517f552ac3130000000000000000000000000000000000000000000000000000000081526004016100bb929190918252602082015260400190565b50600101610713565b50610a236060830183613de5565b90505f03610ab257610aad89895f818110610a4057610a40613db8565b9050602002016020810190610a559190613bb6565b868b8b8a818110610a6857610a68613db8565b9050602002016020810190610a7d9190613bb6565b84610a8b6020880188613bb6565b610a9b6040890160208a01613e46565b610aa860408a018a613de5565b611794565b610fe1565b60408051808201909152600d81527f455354494d4154455f53574150000000000000000000000000000000000000006020909101527f9fbe8fb0ae8f68c4e90aaac8dee895c5ba9596470c68a601101c9d65a103a943610b156060840184613de5565b610b1e91613bd8565b03610b58576040517f5fea03c9000000000000000000000000000000000000000000000000000000008152600481018290526024016100bb565b610aad5f8a8a8a8a8a87610b6f60608b018b613de5565b604051602001610456989796959493929190613e5f565b610b8f85613d6f565b9050855b8015610ea6575f888860018403818110610baf57610baf613db8565b610bc59260206060909202019081019150613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b60018503818110610bf057610bf0613db8565b9050602002016020810190610c059190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16148015610ca55750888860018403818110610c3857610c38613db8565b9050606002016020016020810190610c509190613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b84818110610c7857610c78613db8565b9050602002016020810190610c8d9190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16145b15610cb257506001610dc5565b888860018403818110610cc757610cc7613db8565b9050606002016020016020810190610cdf9190613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b60018503818110610d0a57610d0a613db8565b9050602002016020810190610d1f9190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16148015610dbd5750888860018403818110610d5257610d52613db8565b610d689260206060909202019081019150613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b84818110610d9057610d90613db8565b9050602002016020810190610da59190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16145b1561093f57505f5b610df18989610dd5600186613da5565b818110610de457610de4613db8565b9050606002018285611cdb565b92508585610e00600185613da5565b818110610e0f57610e0f613db8565b90506020020135831115610e7e57828686610e2b600186613da5565b818110610e3a57610e3a613db8565b905060200201356040517f97121c210000000000000000000000000000000000000000000000000000000081526004016100bb929190918252602082015260400190565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01610b93565b50610eb46060830183613de5565b90505f03610f2457610aad89895f818110610ed157610ed1613db8565b9050602002016020810190610ee69190613bb6565b828b8b8a818110610ef957610ef9613db8565b9050602002016020810190610f0e9190613bb6565b610f1789613d6f565b610a8b6020880188613bb6565b60408051808201909152600d81527f455354494d4154455f53574150000000000000000000000000000000000000006020909101527f9fbe8fb0ae8f68c4e90aaac8dee895c5ba9596470c68a601101c9d65a103a943610f876060840184613de5565b610f9091613bd8565b03610fca576040517f5fea03c9000000000000000000000000000000000000000000000000000000008152600481018290526024016100bb565b610fe15f8a8a8a8a8a87610b6f60608b018b613de5565b610fe96102b3565b98975050505050505050565b5f5f846040516020016110089190613f1d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301207fffffffffffffffff00000000000000000000000000000000000000000000000081165f908152600290935290822054909250908190036110cf576040517f722948110000000000000000000000000000000000000000000000000000000081527fffffffffffffffff000000000000000000000000000000000000000000000000831660048201526024016100bb565b608881901c670fffffffffffffff1660c482901c5f80806110f38b87898888612435565b92509250925089156112b857607e86901c601f1660098111156111325761111c60098203612844565b8a8161112a5761112a613f2b565b049950611143565b61113e81600903612844565b8a0299505b6127108a108061115a5750670fffffffffffffff8a115b15611194576040517f17d5c4d2000000000000000000000000000000000000000000000000000000008152600481018b90526024016100bb565b600283048a11156111db576040517ffecbb38c000000000000000000000000000000000000000000000000000000008152600481018b9052602481018490526044016100bb565b620f4240611fff88168b0204808b03848101908402816111fd576111fd613f2b565b0499506064600d89901c607f168202048b038701965089861015611257576040517f473f499f000000000000000000000000000000000000000000000000000000008152600481018b9052602481018790526044016100bb565b94899003946c7e37be2022c0914b2680000000878602048610156112b1576040517fb499466c00000000000000000000000000000000000000000000000000000000815260048101889052602481018790526044016100bb565b505061147d565b608386901c601f1660098111156112eb576112d560098203612844565b8a816112e3576112e3613f2b565b0499506112fc565b6112f781600903612844565b8a0299505b6127108a10806113135750670fffffffffffffff8a115b1561134d576040517f17d5c4d2000000000000000000000000000000000000000000000000000000008152600481018b90526024016100bb565b600282048a1115611394576040517ffecbb38c000000000000000000000000000000000000000000000000000000008152600481018b9052602481018390526044016100bb565b620f4240611fff88168b0204808b03838101908502816113b6576113b6613f2b565b0499506064600d89901c607f168202048b038601955089871015611410576040517f473f499f000000000000000000000000000000000000000000000000000000008152600481018b9052602481018890526044016100bb565b898703965061271085026b033b2e3c9fd0803ce800000087028161143657611436613f2b565b0487101561147a576040517fb499466c00000000000000000000000000000000000000000000000000000000815260048101889052602481018790526044016100bb565b50505b601486901c60031680156114ee575f8b6114b8578984036b033b2e3c9fd0803ce80000008c850102816114b2576114b2613f2b565b046114db565b8a84016b033b2e3c9fd0803ce80000008b850302816114d9576114d9613f2b565b045b90506114ea888a848489612927565b9150505b600181118061150457506001601688901c166001145b15611562577fffffffffffffffff00000000000000000000000000000000000000000000000088165f90815260036020526040902080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000016421790555b50670fffffffffffffff8511806115805750670fffffffffffffff84115b156115e9576040517f9e0db8780000000000000000000000000000000000000000000000000000000081527fffffffffffffffff0000000000000000000000000000000000000000000000008816600482015260248101869052604481018590526064016100bb565b7fffffffffffffffff00000000000000000000000000000000000000000000000087165f908152600260205260409020805470ffffffffffffffffffffffffffffffffff16608887901b1760c486901b1790819055955089156116f0576040805168010000000000000000607d8b901b60418d901b60c08c901c1717178152602081018890527ffbce846c23a724e6e61161894819ec46c90a8d3dd96e90e7342c6ef49ffb539c910160405180910390a1608386901c601f1660098111156116cf576116be6116b9600983613da5565b612844565b6116c8908a613f58565b98506116ea565b6116dd6116b9826009613da5565b6116e7908a613f6f565b98505b50611786565b60408051607d8a901b60418c901b60c08b901c17178152602081018890527ffbce846c23a724e6e61161894819ec46c90a8d3dd96e90e7342c6ef49ffb539c910160405180910390a1607e86901c601f166009811115611769576117586116b9600983613da5565b611762908a613f58565b9850611784565b6117776116b9826009613da5565b611781908a613f6f565b98505b505b505050505050509392505050565b73ffffffffffffffffffffffffffffffffffffffff84166117b3573393505b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8716016117ff576117fa8486612b3f565b61180a565b61180a868587612b88565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff89160161198b57828015611852575034155b15611928576040517fb6a545480000000000000000000000000000000000000000000000000000000081524790339063b6a545489061189b908c908c9088908890600401613fa7565b5f604051808303815f87803b1580156118b2575f5ffd5b505af11580156118c4573d5f5f3e3d5ffd5b505050508781476118d59190613da5565b1015611922576118e58147613da5565b6040517fbdd289ca0000000000000000000000000000000000000000000000000000000081526004810191909152602481018990526044016100bb565b50611c4a565b8634101561196b576040517fbdd289ca000000000000000000000000000000000000000000000000000000008152346004820152602481018890526044016100bb565b8634111561198657611986336119818934613da5565b612b3f565b611c4a565b34156119c3576040517f1841b4e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8215611c3e576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8a16906370a0823190602401602060405180830381865afa158015611a33573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a579190613b9f565b6040517fb6a54548000000000000000000000000000000000000000000000000000000008152909150339063b6a5454890611a9c908c908c9088908890600401613fa7565b5f604051808303815f87803b158015611ab3575f5ffd5b505af1158015611ac5573d5f5f3e3d5ffd5b50506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201528a925083915073ffffffffffffffffffffffffffffffffffffffff8c16906370a0823190602401602060405180830381865afa158015611b35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b599190613b9f565b611b639190613da5565b1015611922576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152819073ffffffffffffffffffffffffffffffffffffffff8b16906370a0823190602401602060405180830381865afa158015611bd3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bf79190613b9f565b611c019190613da5565b6040517faf35ea9e0000000000000000000000000000000000000000000000000000000081526004810191909152602481018990526044016100bb565b611c4a8833308a612c2e565b5050505050505050565b5f611c7d7f7e8134afb5ed35d36cb65e24b9a4712a52bb77d952806c1acf50970d2107797f5490565b905073ffffffffffffffffffffffffffffffffffffffff8116611ccc576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611cd68183610271565b505050565b5f5f84604051602001611cee9190613f1d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301207fffffffffffffffff00000000000000000000000000000000000000000000000081165f90815260029093529082205490925090819003611db5576040517f722948110000000000000000000000000000000000000000000000000000000081527fffffffffffffffff000000000000000000000000000000000000000000000000831660048201526024016100bb565b608881901c670fffffffffffffff1660c482901c5f8080611dd98b87898888612435565b9250925092508915611fb557608386901c601f166009811115611e1857611e0260098203612844565b8a81611e1057611e10613f2b565b049950611e29565b611e2481600903612844565b8a0299505b6127108a1080611e405750670fffffffffffffff8a115b15611e7a576040517f17d5c4d2000000000000000000000000000000000000000000000000000000008152600481018b90526024016100bb565b600282048a1115611ec1576040517ffecbb38c000000000000000000000000000000000000000000000000000000008152600481018b9052602481018390526044016100bb565b898203838b0281611ed457611ed4613f2b565b0498505f89611fff8916620f424090810390820281611ef557611ef5613f2b565b0403998a019990506064600d89901c607f168202048a03870196508a861015611f54576040517f473f499f000000000000000000000000000000000000000000000000000000008152600481018c9052602481018790526044016100bb565b948a9003946c7e37be2022c0914b268000000087860204861015611fae576040517fb499466c00000000000000000000000000000000000000000000000000000000815260048101889052602481018790526044016100bb565b5050612191565b607e86901c601f166009811115611fe857611fd260098203612844565b8a81611fe057611fe0613f2b565b049950611ff9565b611ff481600903612844565b8a0299505b6127108a10806120105750670fffffffffffffff8a115b1561204a576040517f17d5c4d2000000000000000000000000000000000000000000000000000000008152600481018b90526024016100bb565b600283048a1115612091576040517ffecbb38c000000000000000000000000000000000000000000000000000000008152600481018b9052602481018490526044016100bb565b898303828b02816120a4576120a4613f2b565b0498505f89611fff8916620f4240908103908202816120c5576120c5613f2b565b0403998a019990506064600d89901c607f168202048a03860195508a871015612124576040517f473f499f000000000000000000000000000000000000000000000000000000008152600481018c9052602481018890526044016100bb565b8a8703965061271085026b033b2e3c9fd0803ce800000087028161214a5761214a613f2b565b0487101561218e576040517fb499466c00000000000000000000000000000000000000000000000000000000815260048101889052602481018790526044016100bb565b50505b601486901c6003168015612202575f8b6121cc578a84036b033b2e3c9fd0803ce80000008b850102816121c6576121c6613f2b565b046121ef565b8984016b033b2e3c9fd0803ce80000008c850302816121ed576121ed613f2b565b045b90506121fe888a848489612927565b9150505b600181118061221857506001601688901c166001145b15612276577fffffffffffffffff00000000000000000000000000000000000000000000000088165f90815260036020526040902080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000016421790555b50670fffffffffffffff8511806122945750670fffffffffffffff84115b156122fd576040517f9e0db8780000000000000000000000000000000000000000000000000000000081527fffffffffffffffff0000000000000000000000000000000000000000000000008816600482015260248101869052604481018590526064016100bb565b7fffffffffffffffff00000000000000000000000000000000000000000000000087165f908152600260205260409020805470ffffffffffffffffffffffffffffffffff16608887901b1760c486901b1790819055955089156123cd576040805168010000000000000000607d8c901b60418c901b60c08c901c1717178152602081018890527ffbce846c23a724e6e61161894819ec46c90a8d3dd96e90e7342c6ef49ffb539c910160405180910390a1607e86901c601f1660098111156116cf576116be6116b9600983613da5565b60408051607d8b901b60418b901b60c08b901c17178152602081018890527ffbce846c23a724e6e61161894819ec46c90a8d3dd96e90e7342c6ef49ffb539c910160405180910390a1608386901c601f166009811115611769576117586116b9600983613da5565b5f5f5f6001601688901c165f03612570576207ffff603f88901c169250825f036124745763ffffffff601f88901c1660ff601789901c161b925061257e565b61249e7f000000000000000000000000000000000000000000000000000000000000000084612cf1565b73ffffffffffffffffffffffffffffffffffffffff166302c59a686124c660208b018b613bb6565b6124d660408c0160208d01613bb6565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201526044016020604051808303815f875af1158015612545573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125699190613b9f565b925061257e565b61257b88888861315a565b92505b613fff605388901c811690606189901c16600160528a901c811690036125af576125a982828a61344e565b90925090505b5f5f83612710036127108802816125c8576125c8613f2b565b04915050612710828103870204600360148c901c165f6001821115612751578160020361266557507fffffffffffffffff0000000000000000000000000000000000000000000000008b165f90815260036020526040902054602181901c62ffffff166401ffffffff821642038181101561265a5781818c8803028161265057612650613f2b565b048b019a5061265e565b859a505b50506126df565b816003036126df57507fffffffffffffffff0000000000000000000000000000000000000000000000008b165f90815260036020526040902054602181901c62ffffff166401ffffffff82164203818110156126d8578181868d0302816126ce576126ce613f2b565b048b039a506126dc565b849a505b50505b801561275157620fffff604182901c1660ff603983901c161b91508189111561270a5781985061272b565b620fffff605d82901c1660ff605583901c161b91508189101561272b578198505b85612710036127108a028161274257612742613f2b565b0493506127108581038a020492505b6f4b3b4ca85a86c47a098a22400000000084101561277b5761277483850261354d565b91506127a7565b61279a670de0b6b3a76400008404670de0b6b3a764000086040261354d565b670de0b6b3a76400000291505b6b033b2e3c9fd0803ce80000008210156127d1576127c782858d8d6135ff565b909850965061282e565b61282982760a70c3c40a64e6c51999090b65f67d9240000000000000816127fa576127fa613f2b565b0484760a70c3c40a64e6c51999090b65f67d92400000000000008161282157612821613f2b565b048c8e6135ff565b985096505b50969c959098019a505050930195509350505050565b5f8160030361285657506103e8919050565b816009036128695750633b9aca00919050565b816001036128795750600a919050565b815f0361288857506001919050565b8160020361289857506064919050565b816004036128a95750612710919050565b816005036128bb5750620186a0919050565b816006036128cd5750620f4240919050565b816007036128df575062989680919050565b816008036128f257506305f5e100919050565b6040517f42cfde25000000000000000000000000000000000000000000000000000000008152600481018390526024016100bb565b5f613fff605387901c811690606188901c166001605289901c811690036129595761295382828961344e565b90925090505b816127100361271085028161297057612970613f2b565b0491506127108181038502049050607f607089901c81169060778a901c166001606f8b901c811690036129ae576129a882828b613678565b90925090505b6064918203868503028290048601919081038387030204850381871115612a465787600214612a41575050507fffffffffffffffff00000000000000000000000000000000000000000000000086165f90815260026020819052604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffff16622000001790559150612b369050565b612b2e565b80871015612abe5787600314612a41575050507fffffffffffffffff00000000000000000000000000000000000000000000000086165f90815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffff16623000001790555060039050612b36565b87600114612b2e575050507fffffffffffffffff00000000000000000000000000000000000000000000000086165f90815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffff16621000001790555060019050612b36565b879450505050505b95945050505050565b5f5f5f5f5f8587614e20f1905080611cd6576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155a60048201526024016100bb565b5f6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015282602482015260205f6044835f895af13d15601f3d1160015f511416171691505080612c28576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155a60048201526024016100bb565b50505050565b5f6040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff8416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f511416171691505080612cea576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155960048201526024016100bb565b5050505050565b5f6060825f03612d04575f915050613154565b607f8311612dcd576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b16602282015260f884901b7fff000000000000000000000000000000000000000000000000000000000000001660368201526037015b6040516020818303038152906040529050613149565b60ff8311612eaa576040517fd70000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f8100000000000000000000000000000000000000000000000000000000000000603682015260f884901b7fff00000000000000000000000000000000000000000000000000000000000000166037820152603801612db7565b61ffff8311612f88576040517fd80000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f820000000000000000000000000000000000000000000000000000000000000060368201527fffff00000000000000000000000000000000000000000000000000000000000060f085901b166037820152603901612db7565b62ffffff8311613067576040517fd90000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f830000000000000000000000000000000000000000000000000000000000000060368201527fffffff000000000000000000000000000000000000000000000000000000000060e885901b166037820152603a01612db7565b6040517fda0000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f840000000000000000000000000000000000000000000000000000000000000060368201527fffffffff0000000000000000000000000000000000000000000000000000000060e085901b166037820152603b0160405160208183030381529060405290505b805160209091012090505b92915050565b7fffffffffffffffff00000000000000000000000000000000000000000000000081165f90815260036020526040812054601f84901c63ffffffff16601785901c60ff161b906401ffffffff609982901c81169082168181116131bd57816131bf565b805b90506131f47f00000000000000000000000000000000000000000000000000000000000000006207ffff603f8a901c16612cf1565b73ffffffffffffffffffffffffffffffffffffffff166302c59a6861321c60208b018b613bb6565b61322c60408c0160208d01613bb6565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201526044016020604051808303815f875af115801561329b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132bf9190613b9f565b94505f620f4240620fffff608586901c1602824203620fffff607187901c16870202816132ee576132ee613f2b565b0490508486111561339857938401938486111561330d57849550613442565b7fffffffffffffffff00000000000000000000000000000000000000000000000087165f90815260036020908152604080832080547ffffffffffffffffffc000000000000000001ffffffffffffffffffffffffffff1690556002909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff169055613442565b8085116133a5575f6133a9565b8085035b9450848610156133bb57849550613442565b7fffffffffffffffff00000000000000000000000000000000000000000000000087165f90815260036020908152604080832080547ffffffffffffffffffc000000000000000001ffffffffffffffffffffffffffff1690556002909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff1690555b50505050509392505050565b7fffffffffffffffff00000000000000000000000000000000000000000000000081165f908152600460205260408120548190601c81901c620fffff16603082901c6401ffffffff168342828401101561351357505050507fffffffffffffffff00000000000000000000000000000000000000000000000083165f9081526004602090815260408083208390556002909152902080547ffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffff1690555083905082613545565b504281900361352889613fff86168386613760565b61353c89613fff600e88901c168487613760565b95509550505050505b935093915050565b60b5817101000000000000000000000000000000000081106135745760409190911b9060801c5b690100000000000000000081106135905760209190911b9060401c5b6501000000000081106135a85760109190911b9060201c5b630100000081106135be5760089190911b9060101c5b62010000010260121c80820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c908190048111900390565b5f8085850381600282028689026b033b2e3c9fd0803ce80000008702018161362957613629613f2b565b049050613658818202836b033b2e3c9fd0803ce8000000888a02028161365157613651613f2b565b040161354d565b01976b033b2e3c9fd0803ce8000000978902979097049695505050505050565b7fffffffffffffffff00000000000000000000000000000000000000000000000081165f908152600560205260408120548190600e81901c620fffff16602282901c6401ffffffff168342828401101561373d57505050507fffffffffffffffff00000000000000000000000000000000000000000000000083165f9081526005602090815260408083208390556002909152902080547fffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffff1690555083905082613545565b504281900361375189607f86168386613760565b61353c89607f600788901c1684875b5f83851115613786578183858703028161377c5761377c613f2b565b048401905061379f565b8183868603028161379957613799613f2b565b04840390505b949350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146137c8575f5ffd5b50565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f60408385031215613809575f5ffd5b8235613814816137a7565b9150602083013567ffffffffffffffff81111561382f575f5ffd5b8301601f8101851361383f575f5ffd5b803567ffffffffffffffff811115613859576138596137cb565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156138c5576138c56137cb565b6040528181528282016020018710156138dc575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b8035801515811461390a575f5ffd5b919050565b803561390a816137a7565b5f5f83601f84011261392a575f5ffd5b50813567ffffffffffffffff811115613941575f5ffd5b602083019150836020828501011115613958575f5ffd5b9250929050565b5f5f5f5f5f5f5f5f5f5f8a8c0361014081121561397a575f5ffd5b6060811215613987575f5ffd5b508a995061399760608c016138fb565b985060808b0135975060a08b013596506139b360c08c0161390f565b95506139c160e08c016138fb565b94506101008b013567ffffffffffffffff8111156139dd575f5ffd5b6139e98d828e0161391a565b9095509350506101208b013567ffffffffffffffff811115613a09575f5ffd5b613a158d828e0161391a565b915080935050809150509295989b9194979a5092959850565b5f5f83601f840112613a3e575f5ffd5b50813567ffffffffffffffff811115613a55575f5ffd5b6020830191508360208260051b8501011115613958575f5ffd5b5f60808284031215613a7f575f5ffd5b50919050565b5f5f5f5f5f5f5f5f60a0898b031215613a9c575f5ffd5b883567ffffffffffffffff811115613ab2575f5ffd5b613abe8b828c01613a2e565b909950975050602089013567ffffffffffffffff811115613add575f5ffd5b8901601f81018b13613aed575f5ffd5b803567ffffffffffffffff811115613b03575f5ffd5b8b6020606083028401011115613b17575f5ffd5b6020919091019650945060408901359350606089013567ffffffffffffffff811115613b41575f5ffd5b613b4d8b828c01613a2e565b909450925050608089013567ffffffffffffffff811115613b6c575f5ffd5b613b788b828c01613a6f565b9150509295985092959890939650565b5f60208284031215613b98575f5ffd5b5035919050565b5f60208284031215613baf575f5ffd5b5051919050565b5f60208284031215613bc6575f5ffd5b8135613bd1816137a7565b9392505050565b80356020831015613154577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b8035613c1f816137a7565b73ffffffffffffffffffffffffffffffffffffffff1682526020810135613c45816137a7565b73ffffffffffffffffffffffffffffffffffffffff166020830152604090810135910152565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b613cbc8188613c14565b85151560608201528460808201528360a082015260e060c08201525f610fe960e083018486613c6b565b8215158152604060208201525f82518060408401528060208501606085015e5f6060828501015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7f80000000000000000000000000000000000000000000000000000000000000008203613d9f57613d9f613d42565b505f0390565b8181038181111561315457613154613d42565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e18575f5ffd5b83018035915067ffffffffffffffff821115613e32575f5ffd5b602001915036819003821315613958575f5ffd5b5f60208284031215613e56575f5ffd5b613bd1826138fb565b60a080825281018890525f8960c08301825b8b811015613eae578235613e84816137a7565b73ffffffffffffffffffffffffffffffffffffffff16825260209283019290910190600101613e71565b50838103602080860191909152898252019050885f805b8a811015613eea57613ed78484613c14565b6060938401939290920191600101613ec5565b50505060408301879052606083018690528281036080840152613f0e818587613c6b565b9b9a5050505050505050505050565b606081016131548284613c14565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b808202811582820484141761315457613154613d42565b5f82613fa2577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201525f613fdc606083018486613c6b565b969550505050505056fea264697066735822122048314b8dec15e796decf36eb636ff0c09330021781b58dfce741aa70a3f264ab64736f6c634300081d00330000000000000000000000008a5b57d047d284a2a6ec774a8bca2beab2a6c95500000000000000000000000052aa899454998be5b000ad077a46bbe360f4e4970000000000000000000000004ec7b668baf70d4a4b0fc7941a7708a07b6d45be

Deployed Bytecode

0x608060405260043610610037575f3560e01c80637fc9d4ad146100f7578063a3c779fd1461011c578063b5c736e41461012f5761003e565b3661003e57005b5f36606061004a61014d565b335f9081526020819052604090205460011480159061008657503361006d61019e565b73ffffffffffffffffffffffffffffffffffffffff1614155b156100c4576040517fd86ad9cf0000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b5f806100d2848601866137f8565b915091506100e08282610271565b925050506100ec6102b3565b915050805190602001f35b61010a61010536600461395f565b6102d8565b60405190815260200160405180910390f35b61010a61012a366004613a85565b610634565b34801561013a575f5ffd5b5061010a610149366004613b88565b5490565b7fb9cde754d19acfff2b3ccabc66f256d3563a0bc5805da4205f01a9bda38a2df75c15610178575f5ffd5b60017fb9cde754d19acfff2b3ccabc66f256d3563a0bc5805da4205f01a9bda38a2df75d565b6040517fb5c736e40000000000000000000000000000000000000000000000000000000081527fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d610360048201525f907f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e49773ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401602060405180830381865afa158015610248573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061026c9190613b9f565b905090565b60605f5f835160208501865af43d6040519250601f19601f6020830101168301604052808352805f602085013e816102ab57805f5f3e805ffd5b505092915050565b5f7fb9cde754d19acfff2b3ccabc66f256d3563a0bc5805da4205f01a9bda38a2df75d565b5f6102e161014d565b5f8913156104a6576102f48b8b8b610ff5565b90508781101561033a576040517f552ac31300000000000000000000000000000000000000000000000000000000815260048101829052602481018990526044016100bb565b5f82900361039c57891561037b5761037661035860208d018d613bb6565b8a8d602001602081019061036c9190613bb6565b848b8b8b8b611794565b61061e565b61037661038e60408d0160208e01613bb6565b8a61036c60208f018f613bb6565b60408051808201909152600d81527f455354494d4154455f53574150000000000000000000000000000000000000006020909101527f9fbe8fb0ae8f68c4e90aaac8dee895c5ba9596470c68a601101c9d65a103a9436103fc8385613bd8565b03610436576040517f5fea03c9000000000000000000000000000000000000000000000000000000008152600481018290526024016100bb565b61037660018c8c8c85888860405160200161045696959493929190613cb2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526104929291602001613ce6565b604051602081830303815290604052611c54565b6104b98b8b6104b48c613d6f565b611cdb565b9050878111156104ff576040517f97121c2100000000000000000000000000000000000000000000000000000000815260048101829052602481018990526044016100bb565b5f8290036105645789156105435761037661051d60208d018d613bb6565b828d60200160208101906105319190613bb6565b61053a8d613d6f565b8b8b8b8b611794565b61037661055660408d0160208e01613bb6565b8261053160208f018f613bb6565b60408051808201909152600d81527f455354494d4154455f53574150000000000000000000000000000000000000006020909101527f9fbe8fb0ae8f68c4e90aaac8dee895c5ba9596470c68a601101c9d65a103a9436105c48385613bd8565b036105fe576040517f5fea03c9000000000000000000000000000000000000000000000000000000008152600481018290526024016100bb565b61061e60018c8c8c85888860405160200161045696959493929190613cb2565b6106266102b3565b9a9950505050505050505050565b5f61063d61014d565b5f869003610677576040517fd15d5eeb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8561068360018a613da5565b146106c4576040517f88b3170e00000000000000000000000000000000000000000000000000000000815260048101899052602481018790526044016100bb565b828614610707576040517fb932f13700000000000000000000000000000000000000000000000000000000815260048101849052602481018790526044016100bb565b5f851315610b865750835f5b86811015610a15575f88888381811061072e5761072e613db8565b6107449260206060909202019081019150613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b8481811061076c5761076c613db8565b90506020020160208101906107819190613bb6565b73ffffffffffffffffffffffffffffffffffffffff1614801561082157508888838181106107b1576107b1613db8565b90506060020160200160208101906107c99190613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b846001018181106107f4576107f4613db8565b90506020020160208101906108099190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16145b1561082e57506001610971565b88888381811061084057610840613db8565b90506060020160200160208101906108589190613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b8481811061088057610880613db8565b90506020020160208101906108959190613bb6565b73ffffffffffffffffffffffffffffffffffffffff1614801561093357508888838181106108c5576108c5613db8565b6108db9260206060909202019081019150613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b8460010181811061090657610906613db8565b905060200201602081019061091b9190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16145b1561093f57505f610971565b6040517f0a33bc9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61099389898481811061098657610986613db8565b9050606002018285610ff5565b92508585838181106109a7576109a7613db8565b90506020020135831015610a0c57828686848181106109c8576109c8613db8565b905060200201356040517f552ac3130000000000000000000000000000000000000000000000000000000081526004016100bb929190918252602082015260400190565b50600101610713565b50610a236060830183613de5565b90505f03610ab257610aad89895f818110610a4057610a40613db8565b9050602002016020810190610a559190613bb6565b868b8b8a818110610a6857610a68613db8565b9050602002016020810190610a7d9190613bb6565b84610a8b6020880188613bb6565b610a9b6040890160208a01613e46565b610aa860408a018a613de5565b611794565b610fe1565b60408051808201909152600d81527f455354494d4154455f53574150000000000000000000000000000000000000006020909101527f9fbe8fb0ae8f68c4e90aaac8dee895c5ba9596470c68a601101c9d65a103a943610b156060840184613de5565b610b1e91613bd8565b03610b58576040517f5fea03c9000000000000000000000000000000000000000000000000000000008152600481018290526024016100bb565b610aad5f8a8a8a8a8a87610b6f60608b018b613de5565b604051602001610456989796959493929190613e5f565b610b8f85613d6f565b9050855b8015610ea6575f888860018403818110610baf57610baf613db8565b610bc59260206060909202019081019150613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b60018503818110610bf057610bf0613db8565b9050602002016020810190610c059190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16148015610ca55750888860018403818110610c3857610c38613db8565b9050606002016020016020810190610c509190613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b84818110610c7857610c78613db8565b9050602002016020810190610c8d9190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16145b15610cb257506001610dc5565b888860018403818110610cc757610cc7613db8565b9050606002016020016020810190610cdf9190613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b60018503818110610d0a57610d0a613db8565b9050602002016020810190610d1f9190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16148015610dbd5750888860018403818110610d5257610d52613db8565b610d689260206060909202019081019150613bb6565b73ffffffffffffffffffffffffffffffffffffffff168b8b84818110610d9057610d90613db8565b9050602002016020810190610da59190613bb6565b73ffffffffffffffffffffffffffffffffffffffff16145b1561093f57505f5b610df18989610dd5600186613da5565b818110610de457610de4613db8565b9050606002018285611cdb565b92508585610e00600185613da5565b818110610e0f57610e0f613db8565b90506020020135831115610e7e57828686610e2b600186613da5565b818110610e3a57610e3a613db8565b905060200201356040517f97121c210000000000000000000000000000000000000000000000000000000081526004016100bb929190918252602082015260400190565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01610b93565b50610eb46060830183613de5565b90505f03610f2457610aad89895f818110610ed157610ed1613db8565b9050602002016020810190610ee69190613bb6565b828b8b8a818110610ef957610ef9613db8565b9050602002016020810190610f0e9190613bb6565b610f1789613d6f565b610a8b6020880188613bb6565b60408051808201909152600d81527f455354494d4154455f53574150000000000000000000000000000000000000006020909101527f9fbe8fb0ae8f68c4e90aaac8dee895c5ba9596470c68a601101c9d65a103a943610f876060840184613de5565b610f9091613bd8565b03610fca576040517f5fea03c9000000000000000000000000000000000000000000000000000000008152600481018290526024016100bb565b610fe15f8a8a8a8a8a87610b6f60608b018b613de5565b610fe96102b3565b98975050505050505050565b5f5f846040516020016110089190613f1d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301207fffffffffffffffff00000000000000000000000000000000000000000000000081165f908152600290935290822054909250908190036110cf576040517f722948110000000000000000000000000000000000000000000000000000000081527fffffffffffffffff000000000000000000000000000000000000000000000000831660048201526024016100bb565b608881901c670fffffffffffffff1660c482901c5f80806110f38b87898888612435565b92509250925089156112b857607e86901c601f1660098111156111325761111c60098203612844565b8a8161112a5761112a613f2b565b049950611143565b61113e81600903612844565b8a0299505b6127108a108061115a5750670fffffffffffffff8a115b15611194576040517f17d5c4d2000000000000000000000000000000000000000000000000000000008152600481018b90526024016100bb565b600283048a11156111db576040517ffecbb38c000000000000000000000000000000000000000000000000000000008152600481018b9052602481018490526044016100bb565b620f4240611fff88168b0204808b03848101908402816111fd576111fd613f2b565b0499506064600d89901c607f168202048b038701965089861015611257576040517f473f499f000000000000000000000000000000000000000000000000000000008152600481018b9052602481018790526044016100bb565b94899003946c7e37be2022c0914b2680000000878602048610156112b1576040517fb499466c00000000000000000000000000000000000000000000000000000000815260048101889052602481018790526044016100bb565b505061147d565b608386901c601f1660098111156112eb576112d560098203612844565b8a816112e3576112e3613f2b565b0499506112fc565b6112f781600903612844565b8a0299505b6127108a10806113135750670fffffffffffffff8a115b1561134d576040517f17d5c4d2000000000000000000000000000000000000000000000000000000008152600481018b90526024016100bb565b600282048a1115611394576040517ffecbb38c000000000000000000000000000000000000000000000000000000008152600481018b9052602481018390526044016100bb565b620f4240611fff88168b0204808b03838101908502816113b6576113b6613f2b565b0499506064600d89901c607f168202048b038601955089871015611410576040517f473f499f000000000000000000000000000000000000000000000000000000008152600481018b9052602481018890526044016100bb565b898703965061271085026b033b2e3c9fd0803ce800000087028161143657611436613f2b565b0487101561147a576040517fb499466c00000000000000000000000000000000000000000000000000000000815260048101889052602481018790526044016100bb565b50505b601486901c60031680156114ee575f8b6114b8578984036b033b2e3c9fd0803ce80000008c850102816114b2576114b2613f2b565b046114db565b8a84016b033b2e3c9fd0803ce80000008b850302816114d9576114d9613f2b565b045b90506114ea888a848489612927565b9150505b600181118061150457506001601688901c166001145b15611562577fffffffffffffffff00000000000000000000000000000000000000000000000088165f90815260036020526040902080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000016421790555b50670fffffffffffffff8511806115805750670fffffffffffffff84115b156115e9576040517f9e0db8780000000000000000000000000000000000000000000000000000000081527fffffffffffffffff0000000000000000000000000000000000000000000000008816600482015260248101869052604481018590526064016100bb565b7fffffffffffffffff00000000000000000000000000000000000000000000000087165f908152600260205260409020805470ffffffffffffffffffffffffffffffffff16608887901b1760c486901b1790819055955089156116f0576040805168010000000000000000607d8b901b60418d901b60c08c901c1717178152602081018890527ffbce846c23a724e6e61161894819ec46c90a8d3dd96e90e7342c6ef49ffb539c910160405180910390a1608386901c601f1660098111156116cf576116be6116b9600983613da5565b612844565b6116c8908a613f58565b98506116ea565b6116dd6116b9826009613da5565b6116e7908a613f6f565b98505b50611786565b60408051607d8a901b60418c901b60c08b901c17178152602081018890527ffbce846c23a724e6e61161894819ec46c90a8d3dd96e90e7342c6ef49ffb539c910160405180910390a1607e86901c601f166009811115611769576117586116b9600983613da5565b611762908a613f58565b9850611784565b6117776116b9826009613da5565b611781908a613f6f565b98505b505b505050505050509392505050565b73ffffffffffffffffffffffffffffffffffffffff84166117b3573393505b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8716016117ff576117fa8486612b3f565b61180a565b61180a868587612b88565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff89160161198b57828015611852575034155b15611928576040517fb6a545480000000000000000000000000000000000000000000000000000000081524790339063b6a545489061189b908c908c9088908890600401613fa7565b5f604051808303815f87803b1580156118b2575f5ffd5b505af11580156118c4573d5f5f3e3d5ffd5b505050508781476118d59190613da5565b1015611922576118e58147613da5565b6040517fbdd289ca0000000000000000000000000000000000000000000000000000000081526004810191909152602481018990526044016100bb565b50611c4a565b8634101561196b576040517fbdd289ca000000000000000000000000000000000000000000000000000000008152346004820152602481018890526044016100bb565b8634111561198657611986336119818934613da5565b612b3f565b611c4a565b34156119c3576040517f1841b4e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8215611c3e576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8a16906370a0823190602401602060405180830381865afa158015611a33573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a579190613b9f565b6040517fb6a54548000000000000000000000000000000000000000000000000000000008152909150339063b6a5454890611a9c908c908c9088908890600401613fa7565b5f604051808303815f87803b158015611ab3575f5ffd5b505af1158015611ac5573d5f5f3e3d5ffd5b50506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201528a925083915073ffffffffffffffffffffffffffffffffffffffff8c16906370a0823190602401602060405180830381865afa158015611b35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b599190613b9f565b611b639190613da5565b1015611922576040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152819073ffffffffffffffffffffffffffffffffffffffff8b16906370a0823190602401602060405180830381865afa158015611bd3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bf79190613b9f565b611c019190613da5565b6040517faf35ea9e0000000000000000000000000000000000000000000000000000000081526004810191909152602481018990526044016100bb565b611c4a8833308a612c2e565b5050505050505050565b5f611c7d7f7e8134afb5ed35d36cb65e24b9a4712a52bb77d952806c1acf50970d2107797f5490565b905073ffffffffffffffffffffffffffffffffffffffff8116611ccc576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611cd68183610271565b505050565b5f5f84604051602001611cee9190613f1d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301207fffffffffffffffff00000000000000000000000000000000000000000000000081165f90815260029093529082205490925090819003611db5576040517f722948110000000000000000000000000000000000000000000000000000000081527fffffffffffffffff000000000000000000000000000000000000000000000000831660048201526024016100bb565b608881901c670fffffffffffffff1660c482901c5f8080611dd98b87898888612435565b9250925092508915611fb557608386901c601f166009811115611e1857611e0260098203612844565b8a81611e1057611e10613f2b565b049950611e29565b611e2481600903612844565b8a0299505b6127108a1080611e405750670fffffffffffffff8a115b15611e7a576040517f17d5c4d2000000000000000000000000000000000000000000000000000000008152600481018b90526024016100bb565b600282048a1115611ec1576040517ffecbb38c000000000000000000000000000000000000000000000000000000008152600481018b9052602481018390526044016100bb565b898203838b0281611ed457611ed4613f2b565b0498505f89611fff8916620f424090810390820281611ef557611ef5613f2b565b0403998a019990506064600d89901c607f168202048a03870196508a861015611f54576040517f473f499f000000000000000000000000000000000000000000000000000000008152600481018c9052602481018790526044016100bb565b948a9003946c7e37be2022c0914b268000000087860204861015611fae576040517fb499466c00000000000000000000000000000000000000000000000000000000815260048101889052602481018790526044016100bb565b5050612191565b607e86901c601f166009811115611fe857611fd260098203612844565b8a81611fe057611fe0613f2b565b049950611ff9565b611ff481600903612844565b8a0299505b6127108a10806120105750670fffffffffffffff8a115b1561204a576040517f17d5c4d2000000000000000000000000000000000000000000000000000000008152600481018b90526024016100bb565b600283048a1115612091576040517ffecbb38c000000000000000000000000000000000000000000000000000000008152600481018b9052602481018490526044016100bb565b898303828b02816120a4576120a4613f2b565b0498505f89611fff8916620f4240908103908202816120c5576120c5613f2b565b0403998a019990506064600d89901c607f168202048a03860195508a871015612124576040517f473f499f000000000000000000000000000000000000000000000000000000008152600481018c9052602481018890526044016100bb565b8a8703965061271085026b033b2e3c9fd0803ce800000087028161214a5761214a613f2b565b0487101561218e576040517fb499466c00000000000000000000000000000000000000000000000000000000815260048101889052602481018790526044016100bb565b50505b601486901c6003168015612202575f8b6121cc578a84036b033b2e3c9fd0803ce80000008b850102816121c6576121c6613f2b565b046121ef565b8984016b033b2e3c9fd0803ce80000008c850302816121ed576121ed613f2b565b045b90506121fe888a848489612927565b9150505b600181118061221857506001601688901c166001145b15612276577fffffffffffffffff00000000000000000000000000000000000000000000000088165f90815260036020526040902080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000016421790555b50670fffffffffffffff8511806122945750670fffffffffffffff84115b156122fd576040517f9e0db8780000000000000000000000000000000000000000000000000000000081527fffffffffffffffff0000000000000000000000000000000000000000000000008816600482015260248101869052604481018590526064016100bb565b7fffffffffffffffff00000000000000000000000000000000000000000000000087165f908152600260205260409020805470ffffffffffffffffffffffffffffffffff16608887901b1760c486901b1790819055955089156123cd576040805168010000000000000000607d8c901b60418c901b60c08c901c1717178152602081018890527ffbce846c23a724e6e61161894819ec46c90a8d3dd96e90e7342c6ef49ffb539c910160405180910390a1607e86901c601f1660098111156116cf576116be6116b9600983613da5565b60408051607d8b901b60418b901b60c08b901c17178152602081018890527ffbce846c23a724e6e61161894819ec46c90a8d3dd96e90e7342c6ef49ffb539c910160405180910390a1608386901c601f166009811115611769576117586116b9600983613da5565b5f5f5f6001601688901c165f03612570576207ffff603f88901c169250825f036124745763ffffffff601f88901c1660ff601789901c161b925061257e565b61249e7f0000000000000000000000004ec7b668baf70d4a4b0fc7941a7708a07b6d45be84612cf1565b73ffffffffffffffffffffffffffffffffffffffff166302c59a686124c660208b018b613bb6565b6124d660408c0160208d01613bb6565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201526044016020604051808303815f875af1158015612545573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125699190613b9f565b925061257e565b61257b88888861315a565b92505b613fff605388901c811690606189901c16600160528a901c811690036125af576125a982828a61344e565b90925090505b5f5f83612710036127108802816125c8576125c8613f2b565b04915050612710828103870204600360148c901c165f6001821115612751578160020361266557507fffffffffffffffff0000000000000000000000000000000000000000000000008b165f90815260036020526040902054602181901c62ffffff166401ffffffff821642038181101561265a5781818c8803028161265057612650613f2b565b048b019a5061265e565b859a505b50506126df565b816003036126df57507fffffffffffffffff0000000000000000000000000000000000000000000000008b165f90815260036020526040902054602181901c62ffffff166401ffffffff82164203818110156126d8578181868d0302816126ce576126ce613f2b565b048b039a506126dc565b849a505b50505b801561275157620fffff604182901c1660ff603983901c161b91508189111561270a5781985061272b565b620fffff605d82901c1660ff605583901c161b91508189101561272b578198505b85612710036127108a028161274257612742613f2b565b0493506127108581038a020492505b6f4b3b4ca85a86c47a098a22400000000084101561277b5761277483850261354d565b91506127a7565b61279a670de0b6b3a76400008404670de0b6b3a764000086040261354d565b670de0b6b3a76400000291505b6b033b2e3c9fd0803ce80000008210156127d1576127c782858d8d6135ff565b909850965061282e565b61282982760a70c3c40a64e6c51999090b65f67d9240000000000000816127fa576127fa613f2b565b0484760a70c3c40a64e6c51999090b65f67d92400000000000008161282157612821613f2b565b048c8e6135ff565b985096505b50969c959098019a505050930195509350505050565b5f8160030361285657506103e8919050565b816009036128695750633b9aca00919050565b816001036128795750600a919050565b815f0361288857506001919050565b8160020361289857506064919050565b816004036128a95750612710919050565b816005036128bb5750620186a0919050565b816006036128cd5750620f4240919050565b816007036128df575062989680919050565b816008036128f257506305f5e100919050565b6040517f42cfde25000000000000000000000000000000000000000000000000000000008152600481018390526024016100bb565b5f613fff605387901c811690606188901c166001605289901c811690036129595761295382828961344e565b90925090505b816127100361271085028161297057612970613f2b565b0491506127108181038502049050607f607089901c81169060778a901c166001606f8b901c811690036129ae576129a882828b613678565b90925090505b6064918203868503028290048601919081038387030204850381871115612a465787600214612a41575050507fffffffffffffffff00000000000000000000000000000000000000000000000086165f90815260026020819052604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffff16622000001790559150612b369050565b612b2e565b80871015612abe5787600314612a41575050507fffffffffffffffff00000000000000000000000000000000000000000000000086165f90815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffff16623000001790555060039050612b36565b87600114612b2e575050507fffffffffffffffff00000000000000000000000000000000000000000000000086165f90815260026020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffff16621000001790555060019050612b36565b879450505050505b95945050505050565b5f5f5f5f5f8587614e20f1905080611cd6576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155a60048201526024016100bb565b5f6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015282602482015260205f6044835f895af13d15601f3d1160015f511416171691505080612c28576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155a60048201526024016100bb565b50505050565b5f6040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff8416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f511416171691505080612cea576040517fdee51a8a0000000000000000000000000000000000000000000000000000000081526201155960048201526024016100bb565b5050505050565b5f6060825f03612d04575f915050613154565b607f8311612dcd576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b16602282015260f884901b7fff000000000000000000000000000000000000000000000000000000000000001660368201526037015b6040516020818303038152906040529050613149565b60ff8311612eaa576040517fd70000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f8100000000000000000000000000000000000000000000000000000000000000603682015260f884901b7fff00000000000000000000000000000000000000000000000000000000000000166037820152603801612db7565b61ffff8311612f88576040517fd80000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f820000000000000000000000000000000000000000000000000000000000000060368201527fffff00000000000000000000000000000000000000000000000000000000000060f085901b166037820152603901612db7565b62ffffff8311613067576040517fd90000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f830000000000000000000000000000000000000000000000000000000000000060368201527fffffff000000000000000000000000000000000000000000000000000000000060e885901b166037820152603a01612db7565b6040517fda0000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f840000000000000000000000000000000000000000000000000000000000000060368201527fffffffff0000000000000000000000000000000000000000000000000000000060e085901b166037820152603b0160405160208183030381529060405290505b805160209091012090505b92915050565b7fffffffffffffffff00000000000000000000000000000000000000000000000081165f90815260036020526040812054601f84901c63ffffffff16601785901c60ff161b906401ffffffff609982901c81169082168181116131bd57816131bf565b805b90506131f47f0000000000000000000000004ec7b668baf70d4a4b0fc7941a7708a07b6d45be6207ffff603f8a901c16612cf1565b73ffffffffffffffffffffffffffffffffffffffff166302c59a6861321c60208b018b613bb6565b61322c60408c0160208d01613bb6565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201526044016020604051808303815f875af115801561329b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132bf9190613b9f565b94505f620f4240620fffff608586901c1602824203620fffff607187901c16870202816132ee576132ee613f2b565b0490508486111561339857938401938486111561330d57849550613442565b7fffffffffffffffff00000000000000000000000000000000000000000000000087165f90815260036020908152604080832080547ffffffffffffffffffc000000000000000001ffffffffffffffffffffffffffff1690556002909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff169055613442565b8085116133a5575f6133a9565b8085035b9450848610156133bb57849550613442565b7fffffffffffffffff00000000000000000000000000000000000000000000000087165f90815260036020908152604080832080547ffffffffffffffffffc000000000000000001ffffffffffffffffffffffffffff1690556002909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff1690555b50505050509392505050565b7fffffffffffffffff00000000000000000000000000000000000000000000000081165f908152600460205260408120548190601c81901c620fffff16603082901c6401ffffffff168342828401101561351357505050507fffffffffffffffff00000000000000000000000000000000000000000000000083165f9081526004602090815260408083208390556002909152902080547ffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffff1690555083905082613545565b504281900361352889613fff86168386613760565b61353c89613fff600e88901c168487613760565b95509550505050505b935093915050565b60b5817101000000000000000000000000000000000081106135745760409190911b9060801c5b690100000000000000000081106135905760209190911b9060401c5b6501000000000081106135a85760109190911b9060201c5b630100000081106135be5760089190911b9060101c5b62010000010260121c80820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c908190048111900390565b5f8085850381600282028689026b033b2e3c9fd0803ce80000008702018161362957613629613f2b565b049050613658818202836b033b2e3c9fd0803ce8000000888a02028161365157613651613f2b565b040161354d565b01976b033b2e3c9fd0803ce8000000978902979097049695505050505050565b7fffffffffffffffff00000000000000000000000000000000000000000000000081165f908152600560205260408120548190600e81901c620fffff16602282901c6401ffffffff168342828401101561373d57505050507fffffffffffffffff00000000000000000000000000000000000000000000000083165f9081526005602090815260408083208390556002909152902080547fffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffff1690555083905082613545565b504281900361375189607f86168386613760565b61353c89607f600788901c1684875b5f83851115613786578183858703028161377c5761377c613f2b565b048401905061379f565b8183868603028161379957613799613f2b565b04840390505b949350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146137c8575f5ffd5b50565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f60408385031215613809575f5ffd5b8235613814816137a7565b9150602083013567ffffffffffffffff81111561382f575f5ffd5b8301601f8101851361383f575f5ffd5b803567ffffffffffffffff811115613859576138596137cb565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156138c5576138c56137cb565b6040528181528282016020018710156138dc575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b8035801515811461390a575f5ffd5b919050565b803561390a816137a7565b5f5f83601f84011261392a575f5ffd5b50813567ffffffffffffffff811115613941575f5ffd5b602083019150836020828501011115613958575f5ffd5b9250929050565b5f5f5f5f5f5f5f5f5f5f8a8c0361014081121561397a575f5ffd5b6060811215613987575f5ffd5b508a995061399760608c016138fb565b985060808b0135975060a08b013596506139b360c08c0161390f565b95506139c160e08c016138fb565b94506101008b013567ffffffffffffffff8111156139dd575f5ffd5b6139e98d828e0161391a565b9095509350506101208b013567ffffffffffffffff811115613a09575f5ffd5b613a158d828e0161391a565b915080935050809150509295989b9194979a5092959850565b5f5f83601f840112613a3e575f5ffd5b50813567ffffffffffffffff811115613a55575f5ffd5b6020830191508360208260051b8501011115613958575f5ffd5b5f60808284031215613a7f575f5ffd5b50919050565b5f5f5f5f5f5f5f5f60a0898b031215613a9c575f5ffd5b883567ffffffffffffffff811115613ab2575f5ffd5b613abe8b828c01613a2e565b909950975050602089013567ffffffffffffffff811115613add575f5ffd5b8901601f81018b13613aed575f5ffd5b803567ffffffffffffffff811115613b03575f5ffd5b8b6020606083028401011115613b17575f5ffd5b6020919091019650945060408901359350606089013567ffffffffffffffff811115613b41575f5ffd5b613b4d8b828c01613a2e565b909450925050608089013567ffffffffffffffff811115613b6c575f5ffd5b613b788b828c01613a6f565b9150509295985092959890939650565b5f60208284031215613b98575f5ffd5b5035919050565b5f60208284031215613baf575f5ffd5b5051919050565b5f60208284031215613bc6575f5ffd5b8135613bd1816137a7565b9392505050565b80356020831015613154577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b8035613c1f816137a7565b73ffffffffffffffffffffffffffffffffffffffff1682526020810135613c45816137a7565b73ffffffffffffffffffffffffffffffffffffffff166020830152604090810135910152565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b613cbc8188613c14565b85151560608201528460808201528360a082015260e060c08201525f610fe960e083018486613c6b565b8215158152604060208201525f82518060408401528060208501606085015e5f6060828501015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168401019150509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7f80000000000000000000000000000000000000000000000000000000000000008203613d9f57613d9f613d42565b505f0390565b8181038181111561315457613154613d42565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e18575f5ffd5b83018035915067ffffffffffffffff821115613e32575f5ffd5b602001915036819003821315613958575f5ffd5b5f60208284031215613e56575f5ffd5b613bd1826138fb565b60a080825281018890525f8960c08301825b8b811015613eae578235613e84816137a7565b73ffffffffffffffffffffffffffffffffffffffff16825260209283019290910190600101613e71565b50838103602080860191909152898252019050885f805b8a811015613eea57613ed78484613c14565b6060938401939290920191600101613ec5565b50505060408301879052606083018690528281036080840152613f0e818587613c6b565b9b9a5050505050505050505050565b606081016131548284613c14565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b808202811582820484141761315457613154613d42565b5f82613fa2577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201525f613fdc606083018486613c6b565b969550505050505056fea264697066735822122048314b8dec15e796decf36eb636ff0c09330021781b58dfce741aa70a3f264ab64736f6c634300081d0033

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

0000000000000000000000008a5b57d047d284a2a6ec774a8bca2beab2a6c95500000000000000000000000052aa899454998be5b000ad077a46bbe360f4e4970000000000000000000000004ec7b668baf70d4a4b0fc7941a7708a07b6d45be

-----Decoded View---------------
Arg [0] : auth_ (address): 0x8a5B57d047D284A2A6ec774A8BCA2BeaB2A6C955
Arg [1] : liquidity_ (address): 0x52Aa899454998Be5b000Ad077a46Bbe360F4e497
Arg [2] : deployerContract_ (address): 0x4EC7b668BAF70d4A4b0FC7941a7708A07b6d45Be

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000008a5b57d047d284a2a6ec774a8bca2beab2a6c955
Arg [1] : 00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497
Arg [2] : 0000000000000000000000004ec7b668baf70d4a4b0fc7941a7708a07b6d45be


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
0xBbcb91440523216e2b87052A99F69c604A7b6e00
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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