$LONG IS LIVE ON ROBINHOOD CHAIN →NO SHORTS →NO TOKENS UP FRONT →LOSSES FEED THE POOL →DEPOSIT ETH · PICK A MULTIPLIER · EARN LONG →$LONG IS LIVE ON ROBINHOOD CHAIN →NO SHORTS →NO TOKENS UP FRONT →LOSSES FEED THE POOL →DEPOSIT ETH · PICK A MULTIPLIER · EARN LONG →
[ PERMANENT LIQUIDITY ]
THE LP LOCK
Launch LP for $LONG is burned into a one-way locker. The Uniswap V3 position NFT can never leave. The only callable path after lock is fee collection — and only by the immutable owner.
CONTRACT · UniswapV3LpLockerCHAIN · ROBINHOOD 4663OWNER · 0x9096…45ae
[ WHY IT'S SAFE ]
Small surface. Hard guarantees.
4 PROPERTIES[ ONE WAY ]
No unlock path
There is no decreaseLiquidity, no transferOut, no burn-of-principal. Once burnLP succeeds, the NFT stays in the contract forever.
[ OWNER ONLY ]
Two gated functions
burnLP and safeClaim both require msg.sender == owner. The owner address is immutable — set once in the constructor.
[ FEES ONLY ]
Collect, never principal
safeClaim calls Uniswap’s collect and sends token0/token1 fees to the owner. Liquidity stays in the pool.
[ SINGLE NFT ]
Lock once
positionId can be set only once. A second burnLP reverts with AlreadyLocked — no swapping the locked position later.
[ THE FLOW ]
Lock once. Claim forever.
01
Mint LP
Seed the LONG/WETH Uniswap V3 pool. You receive a position NFT.
02
burnLP
Owner approves the locker and calls burnLP. The NFT moves in — permanently.
03
safeClaim
Trading fees accrue on the position. Only the owner can collect them.
[ SURFACE AREA ]
Two functions. That's it.
The entire mutable API is owner-gated. Below is the real logic the locker exposes — nothing else can move the NFT or redirect fees.
burnLP(uint256 tokenId)
Pulls the Uniswap V3 position NFT into the locker and records it. Reverts if already locked or tokenId is zero.
ONLY OWNERfunction burnLP(uint256 tokenId) external onlyOwner {
if (positionId != 0) revert AlreadyLocked();
if (tokenId == 0) revert BadToken();
IERC721(address(positionManager))
.transferFrom(msg.sender, address(this), tokenId);
positionId = tokenId;
emit Locked(tokenId);
}
safeClaim()
Collects accrued V3 trading fees to the owner. Does not touch liquidity. Reverts if nothing is locked yet.
ONLY OWNERfunction safeClaim() external onlyOwner
returns (uint256 amount0, uint256 amount1)
{
uint256 id = positionId;
if (id == 0) revert NothingLocked();
(amount0, amount1) = positionManager.collect(
CollectParams({
tokenId: id,
recipient: owner,
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
emit Claimed(amount0, amount1);
}
[ WHAT ISN'T THERE ]
Absence is the feature.
Safety here is mostly about what the contract cannot do. If a function that could unlock liquidity doesn't exist, it can't be called — by anyone, ever.
- ×decreaseLiquidity
- ×transfer / safeTransfer of the NFT
- ×setOwner / renounce with a new fee sink
- ×emergency withdraw
- ×pause that freezes fee routing to someone else
[ FULL SOURCE ]
UniswapV3LpLocker.sol
GITHUB ↗src/periphery/UniswapV3LpLocker.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {INonfungiblePositionManager} from "../interfaces/IUniswapV3.sol";
contract UniswapV3LpLocker {
address public immutable owner;
INonfungiblePositionManager public immutable positionManager;
uint256 public positionId;
error NotOwner();
error ZeroAddress();
error AlreadyLocked();
error NothingLocked();
error BadToken();
event Locked(uint256 indexed tokenId);
event Claimed(uint256 amount0, uint256 amount1);
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
constructor(address positionManager_, address owner_) {
if (positionManager_ == address(0) || owner_ == address(0)) {
revert ZeroAddress();
}
positionManager = INonfungiblePositionManager(positionManager_);
owner = owner_;
}
function burnLP(uint256 tokenId) external onlyOwner {
if (positionId != 0) revert AlreadyLocked();
if (tokenId == 0) revert BadToken();
IERC721(address(positionManager))
.transferFrom(msg.sender, address(this), tokenId);
positionId = tokenId;
emit Locked(tokenId);
}
function safeClaim() external onlyOwner
returns (uint256 amount0, uint256 amount1)
{
uint256 id = positionId;
if (id == 0) revert NothingLocked();
(amount0, amount1) = positionManager.collect(
INonfungiblePositionManager.CollectParams({
tokenId: id,
recipient: owner,
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
emit Claimed(amount0, amount1);
}
}
[ NEXT ]
Liquidity that can't walk away.
When the locker is deployed and the seed NFT is burned in, this page will point at the live address. Until then the placeholder above is ready to copy — swap it the moment we go live.