S Price: $0.684445 (-10.22%)

Contract Diff Checker

Contract Name:
UniV3LiquidityLocker

Contract Source Code:

File 1 of 1 : UniV3LiquidityLocker

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC721 {
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
    function ownerOf(uint256 tokenId) external view returns (address);
    function approve(address to, uint256 tokenId) external;
    function setApprovalForAll(address operator, bool approved) external;
}

interface IERC721Receiver {
    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
}

interface INonfungiblePositionManager is IERC721 {
    struct CollectParams {
        address recipient;
        uint256 tokenId;
        uint128 amount0Max;
        uint128 amount1Max;
    }

    function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);
}

abstract contract Ownable {
    address private _owner;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor(address initialOwner) {
        _transferOwnership(initialOwner);
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    modifier onlyOwner() {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
        _;
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

contract UniV3LiquidityLocker is Ownable, IERC721Receiver {
    INonfungiblePositionManager public immutable uniswapV3NFT;

    struct LockedPosition {
        address owner;
        uint256 unlockTime;
    }

    mapping(uint256 => LockedPosition) public lockedPositions;

    event LiquidityLocked(address indexed user, uint256 indexed tokenId, uint256 unlockTime);
    event LiquidityUnlocked(address indexed user, uint256 indexed tokenId);
    event FeesCollected(address indexed user, uint256 indexed tokenId, uint256 amount0, uint256 amount1);
    event NFTApproved(address approvedTo);
    event CollectionApprovalSet(address indexed contractAddress, bool approved);

    constructor(address _uniswapV3NFT) Ownable(msg.sender) {
        uniswapV3NFT = INonfungiblePositionManager(_uniswapV3NFT);
    }

    function lockLiquidity(uint256 tokenId, uint256 lockDuration) external {
        require(lockDuration >= 5 minutes, "Minimum lock duration is 5 minutes");
        require(uniswapV3NFT.ownerOf(tokenId) == msg.sender, "You must own the LP NFT");

        uniswapV3NFT.safeTransferFrom(msg.sender, address(this), tokenId);

        lockedPositions[tokenId] = LockedPosition({
            owner: msg.sender,
            unlockTime: block.timestamp + lockDuration
        });

        emit LiquidityLocked(msg.sender, tokenId, block.timestamp + lockDuration);
    }

    function unlockLiquidity(uint256 tokenId) external {
        LockedPosition storage position = lockedPositions[tokenId];

        require(position.owner == msg.sender, "Not the owner of this NFT");
        require(block.timestamp >= position.unlockTime, "Liquidity is still locked");

        uniswapV3NFT.safeTransferFrom(address(this), msg.sender, tokenId);
        delete lockedPositions[tokenId];
        emit LiquidityUnlocked(msg.sender, tokenId);
    }

    /**
     * @dev Grants UniswapV3 Position Manager full approval to manage NFTs owned by this contract.
     * This only needs to be called once per deployment.
     */
    function setApprovalForCollection() external onlyOwner {
        uniswapV3NFT.setApprovalForAll(address(uniswapV3NFT), true);
        emit CollectionApprovalSet(address(uniswapV3NFT), true);
    }

    /**
     * @dev Collects fees from a locked NFT position.
     * @param tokenId The ID of the NFT.
     * @param amount0Max Maximum amount of token0 to collect.
     * @param amount1Max Maximum amount of token1 to collect.
     * @param recipient Address that will receive the fees.
     */
    function collectFees(
        uint256 tokenId,
        uint128 amount0Max,
        uint128 amount1Max,
        address recipient
    ) external payable {
        require(lockedPositions[tokenId].owner == msg.sender, "Not the owner of this NFT");

        INonfungiblePositionManager.CollectParams memory params = INonfungiblePositionManager.CollectParams({
            recipient: recipient,
            tokenId: tokenId,
            amount0Max: amount0Max,
            amount1Max: amount1Max
        });

        (uint256 amount0, uint256 amount1) = uniswapV3NFT.collect{value: msg.value}(params);

        require(amount0 > 0 || amount1 > 0, "No fees available");

        emit FeesCollected(recipient, tokenId, amount0, amount1);
    }

    function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):