XStakingFactory

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/XStakingFactory.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./interfaces/IToken.sol";
import "./interfaces/IXStakingPool.sol";
import "./interfaces/IXStakingFactory.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";

/**
 * @title XStakingFactory
 * @dev This contract is used to deploy and manage XStakingPool contracts.
 * It uses an upgradeable beacon pattern for creating pools, allowing for future upgrades.
 * @custom:oz-upgrades-from XStakingFactoryV1
 */
contract XStakingFactory is
    Initializable,
    Ownable2StepUpgradeable,
    IXStakingFactory,
    ReentrancyGuardUpgradeable
{
    using SafeERC20 for IToken;

    /// @dev 10000 = 100%
    uint256 public constant FEE_DENOMINATOR = 100_00;

    /// @dev 10000 = 100%
    uint256 public constant SLIPPAGE_DENOMINATOR = 1000;

    /// @notice the beacon of BeaconProxy pattern
    UpgradeableBeacon public beacon;

    /// @notice address of smart contract with logic of pool
    IXStakingPool public xstakingPoolImplementation;

    /// @notice address of treasury wallet
    address public treasuryWallet;

    /// @notice records of all deployed staking pools
    address[] public xstakingPools;

    /// @notice the address of USDT
    address[] public depositTokens;

    /// @notice the address of 1inch exchange aggregator
    address public oneInchRouter;

    /// @notice amount of USDT for creation pool
    uint256 public poolCreationFee;

    /// @notice the numerator of staking fee
    uint256 public stakingFeeNumerator;

    /// @notice the numerator of unstaking fee
    uint256 public unstakingFeeNumerator;

    /// @notice the index of deposit token in `depositTokens` array
    mapping(address depositToken => uint256) public depositTokenIndex;

    /// @notice is token is able for depositing
    mapping(address token => bool) public isDepositToken;

    /// @notice is XStakingPool listed
    mapping(address pool => bool) public isXStakingPool;

    struct FeeConfig {
        uint256 from;
        uint256 to;
        uint256 percentage;
        uint256 fixedFee;
    }

    FeeConfig[] public depositFeeConfig;

    FeeConfig[] public withdrawFeeConfig;

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /// @notice Initializes the XStakingFactory with a specified XStakingPool implementation.
    /// @dev Sets the initial XStakingPool implementation and creates an upgradeable beacon.
    /// @param _xstakingPoolImplementation Address of the initial XStakingPool implementation.
    /// @param _depositTokens address of base ERC20 token (USDT)
    /// @param _oneInchRouter address of 1inch router aggregator V5
    /// @param _poolCreationFee amount of USDT for pool creation
    function initialize(
        address _xstakingPoolImplementation,
        address _treasuryWallet,
        address[] memory _depositTokens,
        address _oneInchRouter,
        uint256 _poolCreationFee
    ) public initializer {
        require(
            _xstakingPoolImplementation != address(0) &&
                _treasuryWallet != address(0) &&
                _oneInchRouter != address(0),
            "XStakingFactory: Given address is zero-value"
        );

        __Ownable_init(msg.sender);
        __ReentrancyGuard_init();
        beacon = new UpgradeableBeacon(
            _xstakingPoolImplementation,
            address(this)
        );
        xstakingPoolImplementation = IXStakingPool(_xstakingPoolImplementation);
        treasuryWallet = _treasuryWallet;
        for (uint256 i = 0; i < _depositTokens.length; ) {
            isDepositToken[_depositTokens[i]] = true;
            depositTokenIndex[_depositTokens[i]] = i;
            unchecked {
                i++;
            }
        }

        depositTokens = _depositTokens;

        oneInchRouter = _oneInchRouter;
        poolCreationFee = _poolCreationFee;
    }

    // ------------------------------------------------------------------------
    // OWNER FUNCTIONS

    /// @notice set oneInchRouter address
    /// @dev can be called only by owner
    /// @param _oneInchRouter the address of 1inch router aggregator
    function setOneInchRouter(address _oneInchRouter) public onlyOwner {
        require(
            _oneInchRouter != address(0),
            "XStakingFacroty: oneInchRouter is 0"
        );
        oneInchRouter = _oneInchRouter;
    }

    /// @notice set treasury wallet
    /// @dev can be called only by owner
    function setTreasuryWallet(address _treasuryWallet) public onlyOwner {
        require(
            _treasuryWallet != address(0),
            "XStakingFacroty: treasury wallet is 0"
        );
        treasuryWallet = _treasuryWallet;
    }

    /// @notice sets pool creation fee
    /// @param _poolCreationFee the amount of baseAsset
    function setPoolCreationFee(uint256 _poolCreationFee) public onlyOwner {
        poolCreationFee = _poolCreationFee;
    }

    function setFeesInfo(
        FeeConfig[] calldata fees,
        bool isDeposit
    ) external onlyOwner {
        require(fees.length != 0, "XStakingPool: fees length is 0");

        for (uint256 i = 0; i < fees.length; ) {
            require(
                fees[i].from <= fees[i].to,
                "XStakingPool: fee from should be less than to"
            );
            require(
                fees[i].percentage <= FEE_DENOMINATOR,
                "XStakingPool: percentage should be less than FEE_DENOMINATOR"
            );
            if (fees[i].percentage == 0)
                require(
                    fees[i].fixedFee > 0,
                    "XStakingPool: fixed fee should be greater than 0"
                );
            if (fees[i].percentage != 0)
                require(
                    fees[i].fixedFee == 0,
                    "XStakingPool: fixed fee must be 0"
                );
            if (i > 0) {
                require(
                    fees[i].from > fees[i - 1].to,
                    "XStakingPool: range from should be greater than previous to"
                );
                if (fees[i].percentage == 0) {
                    require(
                        fees[i].fixedFee > 0,
                        "XStakingPool: fixed fee should be greater than 0"
                    );
                }
            }
            unchecked {
                ++i;
            }
        }

        isDeposit ? depositFeeConfig = fees : withdrawFeeConfig = fees;
    }

    /// @notice sweep any token to owner
    /// @param token address of token
    function sweep(address token) public onlyOwner {
        uint256 balanceOfToken = IToken(token).balanceOf(address(this));
        IToken(token).safeTransfer(owner(), balanceOfToken);
    }

    /// @notice Upgrades the XStakingPool implementation to a new contract.
    /// @dev Can only be called by the owner. Updates the beacon with the new implementation address.
    /// @param _xstakingPoolImplementation Address of the new XStakingPool implementation.
    function upgradeTo(address _xstakingPoolImplementation) public onlyOwner {
        xstakingPoolImplementation = IXStakingPool(_xstakingPoolImplementation);
        beacon.upgradeTo(_xstakingPoolImplementation);
    }

    // ------------------------------------------------------------------------
    // USER FUNCTIONS

    /// @notice Deploys a new XStakingPool contract.
    /// @dev Creates a new BeaconProxy pointing to the beacon and initializes the pool.
    /// @param tokens the array of addresses of tokens
    /// @param allocations the allocation for tokens
    /// @return Address of the newly deployed XStakingPool.
    function deployPool(
        address depositToken,
        uint256 capitalizationCap,
        address[] memory tokens,
        uint256[] memory allocations,
        uint256 profitSharingFeeNumerator,
        uint256 initialDepositTokenAmount,
        bytes[] calldata oneInchSwapData,
        string memory description
    ) public nonReentrant returns (address) {
        require(
            isDepositToken[depositToken],
            "XStakingFactory: token is not deposit token"
        );
        uint256 tokensLength = tokens.length;
        require(
            tokensLength == oneInchSwapData.length,
            "XStakingFactory: tokens.length != oneInchSwapData.length"
        );
        uint256 poolId = xstakingPools.length + 1;

        // Staking fee

        uint256 depositTokenAmount = getTotalDepositTokenAmountForDeployPool(
            initialDepositTokenAmount
        );
        {
            IToken(depositToken).safeTransferFrom(
                msg.sender,
                address(this),
                depositTokenAmount
            );

            uint256 stakingFee = calculateFeeAmount(
                initialDepositTokenAmount,
                true
            );
            uint256 totalFee = poolCreationFee + stakingFee;

            IToken(depositToken).safeTransfer(treasuryWallet, totalFee);
        }

        BeaconProxy newPool = new BeaconProxy(address(beacon), bytes(""));
        xstakingPools.push(address(newPool));
        isXStakingPool[address(newPool)] = true;

        IToken(depositToken).forceApprove(
            oneInchRouter,
            initialDepositTokenAmount
        );

        uint256 totalSwappedDepositTokenAmount = 0;

        uint256[] memory tokensAmounts = new uint256[](tokensLength);
        address token;
        for (uint256 i = 0; i < tokensLength; ) {
            token = tokens[i];

            uint256 balanceBefore = IToken(token).balanceOf(address(this));

            uint256 depositTokenBalanceBefore = IToken(depositToken).balanceOf(
                address(this)
            );

            (bool success, ) = oneInchRouter.call(oneInchSwapData[i]);

            uint256 depositTokenBalanceAfter = IToken(depositToken).balanceOf(
                address(this)
            );

            uint256 balanceAfter = IToken(token).balanceOf(address(this));

            uint256 amountOut = balanceAfter - balanceBefore;

            require(
                amountOut > 0,
                "XStakingFactory: 1inch swap out amount is 0"
            );

            require(
                oneInchSwapData[i].length >= 4,
                "XStakingFactory: Incorrect data length"
            );

            (
                ,
                address receiver,
                address srcToken,
                uint256 srcTokenAmount,
                uint256 minReturnAmount
            ) = decodeSwapData(oneInchSwapData[i]);

            require(
                srcTokenAmount ==
                    depositTokenBalanceBefore - depositTokenBalanceAfter,
                "XStakingFactory: srcTokenAmount is not correct"
            );

            require(
                receiver == address(this),
                "XStakingFactory: receiver is not factory"
            );

            require(
                depositToken == address(srcToken),
                "XStakingFactory: deposit token does not match with src token in swap data"
            );

            require(success, "XStakingFactory: 1inch swap failed");

            totalSwappedDepositTokenAmount += srcTokenAmount;

            IToken(token).forceApprove(address(newPool), amountOut);

            tokensAmounts[i] = amountOut;

            require(
                tokensAmounts[i] >= minReturnAmount,
                "XStakingFactory: output amount does not match with encoded amount from swap data"
            );

            unchecked {
                i++;
            }
        }

        require(
            totalSwappedDepositTokenAmount == initialDepositTokenAmount,
            "XStakingFactory: swapped tokens amount does not match with sum of amount in every swap"
        );

        IXStakingPool(address(newPool)).initialize(
            poolId,
            msg.sender,
            capitalizationCap,
            tokens,
            allocations,
            profitSharingFeeNumerator,
            tokensAmounts,
            depositToken,
            initialDepositTokenAmount
        );

        emit DeployPool(
            msg.sender,
            address(newPool),
            poolId,
            tokens,
            allocations,
            description,
            capitalizationCap,
            profitSharingFeeNumerator
        );
        return address(newPool);
    }

    /// @notice return the allocation tokens for deposit using 1inch, when creating pool
    /// @dev this helper view function uses for forming swap request to 1inch API
    /// @param tokens the array of tokens
    /// @param allocations the array of allocations of tokens
    /// @param initialDepositTokenAmount the amount of base token to deposit
    /// @return the array of allocation of depositTokenAmount for swap using 1inch and sum of array elements
    function calcDepositTokenAmountAllocationForDeployPool(
        address[] memory tokens,
        uint256[] memory allocations,
        uint256 initialDepositTokenAmount
    ) public pure returns (uint256[] memory, uint256) {
        require(
            tokens.length == allocations.length,
            "XStakingFactory: not equal length of tokens and allocations"
        );
        uint256[] memory allocatedDepositTokens = new uint256[](tokens.length);
        uint256 totalSumOfAllocatedBaseToken;
        uint256 totalAllocation = 0;
        for (uint256 i = 0; i < allocations.length; ) {
            unchecked {
                totalAllocation += allocations[i];
                i++;
            }
        }
        for (uint256 i = 0; i < tokens.length; ) {
            allocatedDepositTokens[i] =
                (initialDepositTokenAmount * allocations[i]) /
                totalAllocation;
            totalSumOfAllocatedBaseToken += allocatedDepositTokens[i];
            unchecked {
                i++;
            }
        }
        return (allocatedDepositTokens, totalSumOfAllocatedBaseToken);
    }

    function calculateFeeAmount(
        uint256 amount,
        bool isDeposit
    ) public view returns (uint256) {
        FeeConfig memory feeInfo;
        if (isDeposit) {
            uint256 length = depositFeeConfig.length;
            for (uint256 i = 0; i < length; ) {
                if (
                    depositFeeConfig[i].from <= amount &&
                    depositFeeConfig[i].to >= amount
                ) {
                    feeInfo = depositFeeConfig[i];
                }
                unchecked {
                    i++;
                }
            }
        } else {
            uint256 length = withdrawFeeConfig.length;
            for (uint256 i = 0; i < length; ) {
                if (
                    withdrawFeeConfig[i].from <= amount &&
                    withdrawFeeConfig[i].to >= amount
                ) {
                    feeInfo = withdrawFeeConfig[i];
                }
                unchecked {
                    i++;
                }
            }
        }

        if (feeInfo.percentage == 0) return feeInfo.fixedFee;

        return (amount * feeInfo.percentage) / FEE_DENOMINATOR;
    }

    /// @notice returns the total amount of base token for deployment of pool
    function getTotalDepositTokenAmountForDeployPool(
        uint256 initialDepositTokenAmount
    ) public view returns (uint256 depositTokenAmount) {
        uint256 stakingFee = calculateFeeAmount(
            initialDepositTokenAmount,
            true
        );
        depositTokenAmount =
            poolCreationFee +
            initialDepositTokenAmount +
            stakingFee;
    }

    /// @notice Returns an array of all deployed XStakingPool addresses.
    /// @return An array of addresses of all XStakingPools.
    function getXStakingPools() public view returns (address[] memory) {
        return xstakingPools;
    }

    /// @notice Returns a slice of deployed XStakingPool addresses within a specified range.
    /// @dev Fetches pools from the `fromId` up to (but not including) `toId`.
    /// @param fromId The starting index in the list of pools.
    /// @param toId The ending index in the list of pools.
    /// @return xstakingPoolsSlice as array of addresses of XStakingPools in the specified range.
    function getXStakingPoolsByIds(
        uint256 fromId,
        uint256 toId
    ) public view returns (address[] memory xstakingPoolsSlice) {
        require(fromId <= toId, "XStakingFactory: exceeded length of pools");
        require(
            toId <= xstakingPools.length,
            "XStakingFactory: toId exceeds length of pools"
        );
        if (fromId == toId) {
            xstakingPoolsSlice = new address[](1);
            xstakingPoolsSlice[0] = xstakingPools[fromId];
        } else {
            xstakingPoolsSlice = new address[](toId - fromId);
            for (uint256 i = 0; i < toId - fromId; i++) {
                xstakingPoolsSlice[i] = xstakingPools[i + fromId];
            }
        }
        return xstakingPoolsSlice;
    }

    /// @notice Returns the total number of deployed XStakingPools.
    /// @return The number of XStakingPools deployed by this factory.
    function getXStakingPoolsLength() public view returns (uint256) {
        return xstakingPools.length;
    }

    function getDepositToken(uint8 index) external view returns (address) {
        return depositTokens[index];
    }

    function getCurrentFees()
        external
        view
        returns (
            FeeConfig[] memory depositFees_,
            FeeConfig[] memory withdrawFees_
        )
    {
        return (depositFeeConfig, withdrawFeeConfig);
    }

    /// @notice decode swap data for 1inch and return the parameters used in swap
    /// @param data the calldata of swap
    function decodeSwapData(
        bytes calldata data
    )
        public
        view
        returns (
            address sender,
            address receiver,
            address srcToken,
            uint256 srcTokenAmount,
            uint256 minReturnAmount
        )
    {
        bytes4 selector;
        assembly {
            selector := calldataload(data.offset)
        }

        /// @dev `0x0502b1c5` - unoswap selector
        if (selector == bytes4(0x0502b1c5)) {
            (srcToken, srcTokenAmount, minReturnAmount, ) = abi.decode(
                data[4:],
                (address, uint256, uint256, uint256[])
            );
            sender = address(this);
            receiver = address(this);
        }
        /// @dev `0x12aa3caf` - swap selector
        else if (selector == bytes4(0x12aa3caf)) {
            (address executor, SwapDescription memory desc, , ) = abi.decode(
                data[4:], // Skip selector (4 bytes)
                (address, SwapDescription, bytes, bytes)
            );

            sender = executor;
            receiver = desc.dstReceiver;
            srcToken = address(desc.srcToken);
            srcTokenAmount = desc.amount;
            minReturnAmount = desc.minReturnAmount;
        } else if (selector == bytes4(0xe449022e)) {
            uint256[] memory pools;
            (srcTokenAmount, minReturnAmount, pools) = abi.decode(
                data[4:], // Skip selector (4 bytes)
                (uint256, uint256, uint256[])
            );

            address token0 = IUniswapV3Pool(address(uint160(pools[0])))
                .token0();

            address token1 = IUniswapV3Pool(address(uint160(pools[0])))
                .token1();

            if (isDepositToken[token0] && isDepositToken[token1]) {
                revert("XStakingFactory: both tokens are deposit tokens");
            }

            if (!isDepositToken[token0]) {
                srcToken = token1;
            } else {
                srcToken = token0;
            }
            sender = address(this);
            receiver = address(this);
        } else if (selector == bytes4(0x62e238bb)) {
            (
                Order memory order,
                ,
                ,
                uint256 makingAmount,
                uint256 takingAmount,

            ) = abi.decode(
                    data[4:], // Skip selector (4 bytes)
                    (Order, bytes, bytes, uint256, uint256, uint256)
                );

            sender = msg.sender;
            receiver = order.maker;
            srcToken = order.takerAsset;
            srcTokenAmount = takingAmount;
            minReturnAmount = makingAmount;
        } else {
            revert("XStakingFactory: unknown selector");
        }
    }
}
"
    },
    "contracts/interfaces/IToken.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";

interface IToken is IERC20Metadata {


}"
    },
    "contracts/interfaces/IXStakingPool.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IXStakingPool {
    struct SwapDescription {
        IERC20 srcToken;
        IERC20 dstToken;
        address payable srcReceiver;
        address payable dstReceiver;
        uint256 amount;
        uint256 minReturnAmount;
        uint256 flags;
    }

    struct Order {
        uint256 salt;
        address makerAsset;
        address takerAsset;
        address maker;
        address receiver;
        address allowedSender; // equals to Zero address on public orders
        uint256 makingAmount;
        uint256 takingAmount;
        uint256 offsets;
        bytes interactions; // concat(makerAssetData, takerAssetData, getMakingAmount, getTakingAmount, predicate, permit, preIntercation, postInteraction)
    }

    event TokenSwap(
        address token,
        uint256 tokenAmount,
        uint256 baseTokenAmount
    );

    event TokensAmounts(address[] tokens, uint256[] tokenAmounts);

    event Volume(uint256 amount);

    event PoolCapitalization(address pool, uint256 capitalization);

    event UserCapitalization(
        address pool,
        address user,
        uint256 capitalization
    );

    event Deposit(
        address pool,
        address depositor,
        uint256 amount,
        uint256[] userTokenAmounts
    );

    event Withdraw(
        address pool,
        address depositor,
        uint256 amount,
        uint256[] userTokenAmounts
    );

    event DepositStatusUpdated(bool isPaused);

    function initialize(
        uint256 _poolId,
        address _poolOwner,
        uint256 _capitalizationCap,
        address[] memory _tokens,
        uint256[] memory _allocations,
        uint256 _profitSharingFeeNumerator,
        uint256[] memory _tokensAmounts,
        address initialDepositToken,
        uint256 initialBaseTokenAmount
    ) external;

    function deposit(
        address depositToken,
        uint256 baseTokenAmount,
        bytes[] calldata oneInchSwapData
    ) external returns (uint256);

    function depositTo(
        address depositToken,
        address to,
        uint256 baseTokenAmount,
        bytes[] calldata oneInchSwapData
    ) external returns (uint256);

    function withdraw(
        address depositToken,
        uint256 amountLP,
        bytes[] calldata oneInchSwapData
    ) external returns (uint256);
}"
    },
    "contracts/interfaces/IXStakingFactory.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IXStakingFactory {
    /// @notice argument for oneInch swap function.
    struct SwapDescription {
        IERC20 srcToken;
        IERC20 dstToken;
        address payable srcReceiver;
        address payable dstReceiver;
        uint256 amount;
        uint256 minReturnAmount;
        uint256 flags;
    }

    struct Order {
        uint256 salt;
        address makerAsset;
        address takerAsset;
        address maker;
        address receiver;
        address allowedSender; // equals to Zero address on public orders
        uint256 makingAmount;
        uint256 takingAmount;
        uint256 offsets;
        bytes interactions; // concat(makerAssetData, takerAssetData, getMakingAmount, getTakingAmount, predicate, permit, preIntercation, postInteraction)
    }

    function FEE_DENOMINATOR() external view returns (uint256);

    function treasuryWallet() external view returns (address);

    function oneInchRouter() external view returns (address);

    function getDepositToken(uint8 index) external view returns (address);

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

    function isDepositToken(address token) external view returns (bool);

    function isXStakingPool(address pool) external view returns (bool);

    function decodeSwapData(bytes calldata data)
        external
        returns (address sender, address receiver, address srcToken, uint256 srcTokenAmount, uint256 minReturnAmount);

    function calculateFeeAmount(
        uint256 amount,
        bool isDeposit
    ) external view returns (uint256);

    event DeployPool(
        address deployer,
        address pool,
        uint256 poolId,
        address[] tokens,
        uint256[] allocations,
        string description,
        uint256 capitalizationCap,
        uint256 profitSharingFeeNumerator
    );
}
"
    },
    "node_modules/@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import './pool/IUniswapV3PoolImmutables.sol';
import './pool/IUniswapV3PoolState.sol';
import './pool/IUniswapV3PoolDerivedState.sol';
import './pool/IUniswapV3PoolActions.sol';
import './pool/IUniswapV3PoolOwnerActions.sol';
import './pool/IUniswapV3PoolEvents.sol';

/// @title The interface for a Uniswap V3 Pool
/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform
/// to the ERC20 specification
/// @dev The pool interface is broken up into many smaller pieces
interface IUniswapV3Pool is
    IUniswapV3PoolImmutables,
    IUniswapV3PoolState,
    IUniswapV3PoolDerivedState,
    IUniswapV3PoolActions,
    IUniswapV3PoolOwnerActions,
    IUniswapV3PoolEvents
{

}
"
    },
    "node_modules/@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

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

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

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
        assembly {
            $.slot := ReentrancyGuardStorageLocation
        }
    }

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

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

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if ($._status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        $._status = ENTERED;
    }

    function _nonReentrantAfter() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        return $._status == ENTERED;
    }
}
"
    },
    "node_modules/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/BeaconProxy.sol)

pragma solidity ^0.8.20;

import {IBeacon} from "./IBeacon.sol";
import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";

/**
 * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
 *
 * The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an
 * immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] so that it can be accessed externally.
 *
 * CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust
 * the beacon to not upgrade the implementation maliciously.
 *
 * IMPORTANT: Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in
 * an inconsistent state where the beacon storage slot does not match the beacon address.
 */
contract BeaconProxy is Proxy {
    // An immutable address for the beacon to avoid unnecessary SLOADs before each delegate call.
    address private immutable _beacon;

    /**
     * @dev Initializes the proxy with `beacon`.
     *
     * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
     * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
     * constructor.
     *
     * Requirements:
     *
     * - `beacon` must be a contract with the interface {IBeacon}.
     * - If `data` is empty, `msg.value` must be zero.
     */
    constructor(address beacon, bytes memory data) payable {
        ERC1967Utils.upgradeBeaconToAndCall(beacon, data);
        _beacon = beacon;
    }

    /**
     * @dev Returns the current implementation address of the associated beacon.
     */
    function _implementation() internal view virtual override returns (address) {
        return IBeacon(_getBeacon()).implementation();
    }

    /**
     * @dev Returns the beacon.
     */
    function _getBeacon() internal view virtual returns (address) {
        return _beacon;
    }
}
"
    },
    "node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

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

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

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

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

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

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

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

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

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

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

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

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}
"
    },
    "node_modules/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/UpgradeableBeacon.sol)

pragma solidity ^0.8.20;

import {IBeacon} from "./IBeacon.sol";
import {Ownable} from "../../access/Ownable.sol";

/**
 * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
 * implementation contract, which is where they will delegate all function calls.
 *
 * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
 */
contract UpgradeableBeacon is IBeacon, Ownable {
    address private _implementation;

    /**
     * @dev The `implementation` of the beacon is invalid.
     */
    error BeaconInvalidImplementation(address implementation);

    /**
     * @dev Emitted when the implementation returned by the beacon is changed.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon.
     */
    constructor(address implementation_, address initialOwner) Ownable(initialOwner) {
        _setImplementation(implementation_);
    }

    /**
     * @dev Returns the current implementation address.
     */
    function implementation() public view virtual returns (address) {
        return _implementation;
    }

    /**
     * @dev Upgrades the beacon to a new implementation.
     *
     * Emits an {Upgraded} event.
     *
     * Requirements:
     *
     * - msg.sender must be the owner of the contract.
     * - `newImplementation` must be a contract.
     */
    function upgradeTo(address newImplementation) public virtual onlyOwner {
        _setImplementation(newImplementation);
    }

    /**
     * @dev Sets the implementation contract address for this beacon
     *
     * Requirements:
     *
     * - `newImplementation` must be a contract.
     */
    function _setImplementation(address newImplementation) private {
        if (newImplementation.code.length == 0) {
            revert BeaconInvalidImplementation(newImplementation);
        }
        _implementation = newImplementation;
        emit Upgraded(newImplementation);
    }
}
"
    },
    "node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

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

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

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

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}
"
    },
    "node_modules/@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {OwnableUpgradeable} from "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step
    struct Ownable2StepStorage {
        address _pendingOwner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;

    function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {
        assembly {
            $.slot := Ownable2StepStorageLocation
        }
    }

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    function __Ownable2Step_init() internal onlyInitializing {
    }

    function __Ownable2Step_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        return $._pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        $._pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        delete $._pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}
"
    },
    "node_modules/@openzeppelin/contracts/interfaces/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
"
    },
    "node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}
"
    },
    "node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

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

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

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

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

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

    /// @notice The maximum amount of position liquidity that can use any tick in the range
    /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
    /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
    /// @return The max amount of liquidity per tick
    function maxLiquidityPerTick() external view returns (uint128);
}
"
    },
    "node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Pool state that can change
/// @notice These methods compose the pool's state, and can change with any frequency including multiple times
/// per transaction
interface IUniswapV3PoolState {
    /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas
    /// when accessed externally.
    /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
    /// tick The current tick of the pool, i.e. according to the last tick transition that was run.
    /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
    /// boundary.
    /// observationIndex The index of the last oracle observation that was written,
    /// observationCardinality The current maximum number of observations stored in the pool,
    /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
    /// feeProtocol The protocol fee for both tokens of the pool.
    /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0
    /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.
    /// unlocked Whether the pool is currently locked to reentrancy
    function slot0()
        external
        view
        returns (
            uint160 sqrtPriceX96,
            int24 tick,
            uint16 observationIndex,
            uint16 observationCardinality,
            uint16 observationCardinalityNext,
            uint8 feeProtocol,
            bool unlocked
        );

    /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
    /// @dev This value can overflow the uint256
    function feeGrowthGlobal0X128() external view returns (uint256);

    /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
    /// @dev This value can overflow the uint256
    function feeGrowthGlobal1X128() external view returns (uint256);

    /// @notice The amounts of token0 and token1 that are owed to the protocol
    /// @dev Protocol fees will never exceed uint128 max in either token
    function protocolFees() external view returns (uint128 token0, uint128 token1);

    /// @notice The currently in range liquidity available to the pool
    /// @dev This value has no relationship to the total liquidity across all ticks
    function liquidity() external view returns (uint128);

    /// @notice Look up information about a specific tick in the pool
    /// @param tick The tick to look up
    /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or
    /// tick upper,
    /// liquidityNet how much liquidity changes when the pool price crosses the tick,
    /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,
    /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,
    /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick
    /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,
    /// secondsOutside the seconds spent on the other side of the tick from the current tick,
    /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.
    /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.
    /// In addition, these values are only relative and must be used only in comparison to previous snapshots for
    /// a specific position.
    function ticks(int24 tick)
        external
        view
        returns (
            uint128 liquidityGross,
            int128 liquidityNet,
            uint256 feeGrowthOutside0X128,
            uint256 feeGrowthOutside1X128,
            int56 tickCumulativeOutside,
            uint160 secondsPerLiquidityOutsideX128,
            uint32 secondsOutside,
            bool initialized
        );

    /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap fo

Tags:
ERC20, Multisig, Mintable, Burnable, Swap, Liquidity, Staking, Upgradeable, Multi-Signature, Factory, Oracle|addr:0x2dcd476c407f6b92284768e790b3dacf8f309090|verified:true|block:23627849|tx:0x8df3a3abac1ad3c6d2de18787531efd6e2a594569e9a22d52ac804f504c5a5bc|first_check:1761072910

Submitted on: 2025-10-21 20:55:11

Comments

Log in to comment.

No comments yet.