How to Deploy upgradable smart contracts

Hi,

I need to deploy Market.sol. It is an upgradable smart contract. Can anyone help me with its deployment script.

Market.sol Contract ->

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "./IMarket.sol";
import "../OwnableContract.sol";
import "../IComplexDoNFT.sol";
import "../dualRoles/wrap/IWrapNFT.sol";

contract Market is OwnableContract, ReentrancyGuardUpgradeable, IMarket {
    uint64 private constant E5 = 1e5;
    mapping(address => mapping(uint256 => Lending)) internal lendingMap;
    mapping(address => mapping(uint256 => address)) internal privateOrderMap;
    mapping(address => mapping(uint256 => PaymentNormal))
        internal paymentNormalMap;
    mapping(address => mapping(address => uint256)) internal royaltyMap;
    mapping(address => uint256) public balanceOfFee;
    address payable public beneficiary;
    uint256 private fee;
    uint64 public maxIndate;
    bool public isPausing;
    bool public supportERC20;

    function initialize(address owner_, address  admin_  ) public initializer {
        __ReentrancyGuard_init();
        initOwnableContract(owner_, admin_);  
        maxIndate = 365 days;
        fee = 2500;
    }

    function onlyApprovedOrOwner(
        address spender,
        address nftAddress,
        uint256 nftId
    ) internal view {
        address _owner = ERC721(nftAddress).ownerOf(nftId);
        require(
            spender == _owner ||
                ERC721(nftAddress).getApproved(nftId) == spender ||
                ERC721(nftAddress).isApprovedForAll(_owner, spender),
            "only approved or owner"
        );
    }

    modifier whenNotPaused() {
        require(!isPausing, "is pausing");
        _;
    }

    function mintAndCreateLendOrder(
        address doNftAddress,
        uint256 oNftId,
        uint64 maxEndTime,
        uint64 minDuration,
        uint256 pricePerDay,
        address paymentToken
    ) public nonReentrant {
        uint256 nftId = _mintV(doNftAddress, oNftId, maxEndTime);
        createLendOrder(
            doNftAddress,
            nftId,
            maxEndTime,
            minDuration,
            pricePerDay,
            paymentToken
        );
    }

    function mintAndCreatePrivateLendOrder(
        address doNftAddress,
        uint256 oNftId,
        uint64 maxEndTime,
        uint64 minDuration,
        uint256 pricePerDay,
        address paymentToken,
        address renter,
        OrderType orderType
    ) public nonReentrant {
        uint256 nftId = _mintV(doNftAddress, oNftId, maxEndTime);
        createPrivateLendOrder(
            doNftAddress,
            nftId,
            maxEndTime,
            minDuration,
            pricePerDay,
            paymentToken,
            renter,
            orderType
        );
    }

    function _mintV(
        address doNftAddress,
        uint256 oNftId,
        uint64 maxEndTime
    ) internal returns (uint256 nftId) {
        address oNftAddress = IComplexDoNFT(doNftAddress)
            .getOriginalNftAddress();
        if (
            IERC165(oNftAddress).supportsInterface(type(IWrapNFT).interfaceId)
        ) {
            address gameNFTAddress = IWrapNFT(oNftAddress).originalAddress();
            bool isStaked = ERC721(gameNFTAddress).ownerOf(oNftId) ==
                oNftAddress;
            if (isStaked) {
                onlyApprovedOrOwner(msg.sender, oNftAddress, oNftId);
            } else {
                onlyApprovedOrOwner(msg.sender, gameNFTAddress, oNftId);
            }
        } else {
            onlyApprovedOrOwner(msg.sender, oNftAddress, oNftId);
        }
        require(maxEndTime > block.timestamp, "invalid maxEndTime");
        nftId = IComplexDoNFT(doNftAddress).mintVNft(oNftId);
    }

    function createLendOrder(
        address nftAddress,
        uint256 nftId,
        uint64 maxEndTime,
        uint64 minDuration,
        uint256 pricePerDay,
        address paymentToken
    ) public whenNotPaused {
        delete privateOrderMap[nftAddress][nftId];
        paymentNormalMap[nftAddress][nftId] = PaymentNormal(
            paymentToken,
            pricePerDay
        );
        _createLendOrder(
            nftAddress,
            nftId,
            maxEndTime,
            minDuration,
            pricePerDay,
            paymentToken,
            OrderType.Public,
            PaymentType.Normal,
            address(0)
        );
    }

    function createPrivateLendOrder(
        address nftAddress,
        uint256 nftId,
        uint64 maxEndTime,
        uint64 minDuration,
        uint256 pricePerDay,
        address paymentToken,
        address renter,
        OrderType orderType
    ) public whenNotPaused {
        privateOrderMap[nftAddress][nftId] = renter;
        paymentNormalMap[nftAddress][nftId] = PaymentNormal(
            paymentToken,
            pricePerDay
        );
        _createLendOrder(
            nftAddress,
            nftId,
            maxEndTime,
            minDuration,
            pricePerDay,
            paymentToken,
            orderType,
            PaymentType.Normal,
            renter
        );
    }

    function _createLendOrder(
        address nftAddress,
        uint256 nftId,
        uint64 maxEndTime,
        uint64 minDuration,
        uint256 pricePerDay,
        address paymentToken,
        OrderType orderType,
        PaymentType paymentType,
        address renter
    ) internal {
        onlyApprovedOrOwner(msg.sender, nftAddress, nftId);
        require(maxEndTime > block.timestamp, "invalid maxEndTime");
        require(
            minDuration <= IComplexDoNFT(nftAddress).getMaxDuration(),
            "Error:minDuration > max"
        );
        require(
            IERC165(nftAddress).supportsInterface(
                type(IComplexDoNFT).interfaceId
            ),
            "not doNFT"
        );
        (, , uint64 dEnd) = IComplexDoNFT(nftAddress).getDurationByIndex(
            nftId,
            0
        );
        if (maxEndTime > dEnd) {
            maxEndTime = dEnd;
        }
        if (maxEndTime > block.timestamp + maxIndate) {
            maxEndTime = uint64(block.timestamp) + maxIndate;
        }

        address _owner = ERC721(nftAddress).ownerOf(nftId);
        Lending storage lending = lendingMap[nftAddress][nftId];
        lending.lender = _owner;
        lending.nftAddress = nftAddress;
        lending.nftId = nftId;
        lending.maxEndTime = maxEndTime;
        lending.minDuration = minDuration;
        lending.nonce = IComplexDoNFT(nftAddress).getNonce(nftId);
        lending.createTime = uint64(block.timestamp);
        lending.orderType = orderType;
        lending.paymentType = paymentType;

        emit CreateLendOrder(
            _owner,
            nftAddress,
            nftId,
            maxEndTime,
            minDuration,
            pricePerDay,
            paymentToken,
            renter,
            orderType
        );
    }

    function cancelLendOrder(address nftAddress, uint256 nftId)
        public
        whenNotPaused
    {
        onlyApprovedOrOwner(msg.sender, nftAddress, nftId);
        delete lendingMap[nftAddress][nftId];
        delete paymentNormalMap[nftAddress][nftId];
        delete privateOrderMap[nftAddress][nftId];
        emit CancelLendOrder(msg.sender, nftAddress, nftId);
    }

    function getLendOrder(address nftAddress, uint256 nftId)
        public
        view
        returns (Lending memory)
    {
        return lendingMap[nftAddress][nftId];
    }

    function getRenterOfPrivateLendOrder(address nftAddress, uint256 nftId)
        external
        view
        returns (address)
    {
        return privateOrderMap[nftAddress][nftId];
    }

    function getPaymentNormal(address nftAddress, uint256 nftId)
        external
        view
        returns (PaymentNormal memory)
    {
        return paymentNormalMap[nftAddress][nftId];
    }

    function fulfillOrderNow(
        address nftAddress,
        uint256 nftId,
        uint256 durationId,
        uint64 duration,
        address user
    ) public payable virtual whenNotPaused nonReentrant returns (uint256 tid) {
        require(isLendOrderValid(nftAddress, nftId), "invalid order");
        Lending storage lending = lendingMap[nftAddress][nftId];
        if (lending.orderType == OrderType.Private) {
            require(
                msg.sender == privateOrderMap[nftAddress][nftId],
                "invalid renter"
            );
        }
        uint64 endTime = uint64(block.timestamp + duration - 1);
        if (endTime > lending.maxEndTime) {
            endTime = lending.maxEndTime;
        }
        (, uint64 dEnd) = IComplexDoNFT(nftAddress).getDuration(durationId);
        if (endTime > dEnd) {
            endTime = dEnd;
        }
        uint64 startTime = uint64(block.timestamp);
        if (!(endTime == dEnd || endTime == lending.maxEndTime)) {
            require(duration >= lending.minDuration, "duration < minDuration");
        }
        distributePayment(nftAddress, nftId, startTime, endTime);
        tid = IComplexDoNFT(nftAddress).mint(
            nftId,
            durationId,
            startTime,
            endTime,
            msg.sender,
            user
        );
        PaymentNormal storage pNormal = paymentNormalMap[nftAddress][nftId];
        emit FulfillOrder(
            msg.sender,
            lending.lender,
            nftAddress,
            nftId,
            startTime,
            endTime,
            pNormal.pricePerDay,
            tid,
            pNormal.token
        );
    }

    function distributePayment(
        address nftAddress,
        uint256 nftId,
        uint64 startTime,
        uint64 endTime
    )
        internal
        returns (
            uint256 totalPrice,
            uint256 leftTotalPrice,
            uint256 curFee,
            uint256 curRoyalty
        )
    {
        PaymentNormal storage pNormal = paymentNormalMap[nftAddress][nftId];
        totalPrice = (pNormal.pricePerDay * (endTime - startTime + 1)) / 86400;
        curFee = (totalPrice * fee) / E5;
        curRoyalty =
            (totalPrice * IComplexDoNFT(nftAddress).getRoyaltyFee()) /
            E5;
        leftTotalPrice = totalPrice - curFee - curRoyalty;

        royaltyMap[nftAddress][pNormal.token] += curRoyalty;
        balanceOfFee[pNormal.token] += curFee;

        if (pNormal.token == address(0)) {
            require(msg.value >= totalPrice, "payment is not enough");
            Address.sendValue(
                payable(ERC721(nftAddress).ownerOf(nftId)),
                leftTotalPrice
            );
            if (msg.value > totalPrice) {
                Address.sendValue(payable(msg.sender), msg.value - totalPrice);
            }
        } else {
            uint256 balance_before = IERC20(pNormal.token).balanceOf(
                address(this)
            );
            SafeERC20.safeTransferFrom(
                IERC20(pNormal.token),
                msg.sender,
                address(this),
                totalPrice
            );
            uint256 balance_after = IERC20(pNormal.token).balanceOf(
                address(this)
            );
            require(
                balance_before + totalPrice == balance_after,
                "not support burn ERC20"
            );
            SafeERC20.safeTransfer(
                IERC20(pNormal.token),
                ERC721(nftAddress).ownerOf(nftId),
                leftTotalPrice
            );
        }
    }

    function setFee(uint256 fee_) public onlyAdmin {
        require(fee_ <= 1e4, "invalid fee");
        fee = fee_;
    }

    function getFee() public view returns (uint256) {
        return fee;
    }

    function setMarketBeneficiary(address payable beneficiary_)
        public
        onlyOwner
    {
        beneficiary = beneficiary_;
    }

    function claimFee(address[] calldata paymentTokens)
        public
        whenNotPaused
        nonReentrant
    {
        require(msg.sender == beneficiary, "not beneficiary");
        for (uint256 index = 0; index < paymentTokens.length; index++) {
            uint256 balance = balanceOfFee[paymentTokens[index]];
            if (balance > 0) {
                if (paymentTokens[index] == address(0)) {
                    Address.sendValue(beneficiary, balance);
                } else {
                    SafeERC20.safeTransfer(
                        IERC20(paymentTokens[index]),
                        beneficiary,
                        balance
                    );
                }
                balanceOfFee[paymentTokens[index]] = 0;
            }
        }
    }

    function balanceOfRoyalty(address nftAddress, address paymentToken)
        public
        view
        returns (uint256)
    {
        return royaltyMap[nftAddress][paymentToken];
    }

    function claimRoyalty(address nftAddress, address[] calldata paymentTokens)
        public
        whenNotPaused
        nonReentrant
    {
        address payable _beneficiary = IComplexDoNFT(nftAddress)
            .getBeneficiary();
        require(msg.sender == _beneficiary, "not beneficiary");
        for (uint256 index = 0; index < paymentTokens.length; index++) {
            uint256 balance = royaltyMap[nftAddress][paymentTokens[index]];
            if (balance > 0) {
                if (paymentTokens[index] == address(0)) {
                    Address.sendValue(_beneficiary, balance);
                } else {
                    SafeERC20.safeTransfer(
                        IERC20(paymentTokens[index]),
                        _beneficiary,
                        balance
                    );
                }
                royaltyMap[nftAddress][paymentTokens[index]] = 0;
            }
        }
    }

    function isLendOrderValid(address nftAddress, uint256 nftId)
        public
        view
        returns (bool)
    {
        Lending storage lending = lendingMap[nftAddress][nftId];
        if (isPausing) {
            return false;
        }
        return
            lending.nftId > 0 &&
            lending.maxEndTime > block.timestamp &&
            lending.nonce == IComplexDoNFT(nftAddress).getNonce(nftId);
    }

    function setPause(bool pause_) public onlyAdmin {
        isPausing = pause_;
        if (isPausing) {
            emit Paused(address(this));
        } else {
            emit Unpaused(address(this));
        }
    }

    function setMaxIndate(uint64 max_) public onlyAdmin {
        maxIndate = max_;
    }

    function multicall(bytes[] calldata data)
        external
        returns (bytes[] memory results)
    {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(
                data[i]
            );
            if (success) {
                results[i] = result;
            }
        }
        return results;
    }
}

I think you can use the plugin to do this, such as Hardhat and Truffle,