LpHolder
0x9ca167e52a86e54e49ebf813468e6f2be6a94c57
Verification
Verified
v0.8.20+commit.a1b79de6
Type
Contract
2,338 bytes
ABI entries
20
3 read · 6 write
License
none
Contract information
- Address
- 0x9ca167e52a86e54e49ebf813468e6f2be6a94c57
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.20+commit.a1b79de6
- Optimization
- Enabled
- Creator
- 0xCB962B93BD…06c2D67929
- Creation tx
- 0x2d5ee090e1…a620369e6a
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (3)
UNISWAP_V3_NFT_MANAGER() → address
feeReceiver() → address
owner() → address
Events (2)
FeeReceiverSetOwnershipTransferred
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_nftManager",
"type": "address"
},
{
"internalType": "address",
"name": "_feeReceiver",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "address",
"name": "target",
"type": "address"
}
],
"name": "AddressEmptyCode",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "AddressInsufficientBalance",
"type": "error"
},
{
"inputs": [],
"name": "FailedInnerCall",
"type": "error"
},
{
"inputs": [],
"name": "LpHolder__ZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "LpHolder__ZeroLength",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "newFeeReceiver",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "oldFeeReceiver",
"type": "address"
}
],
"name": "FeeReceiverSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [],
"name": "UNISWAP_V3_NFT_MANAGER",
"outputs": [
{
"internalType": "contract INonfungiblePositionManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "tokenIds",
"type": "uint256[]"
}
],
"name": "collectFees",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "feeReceiver",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"name": "onERC721Received",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_feeReceiver",
"type": "address"
}
],
"name": "setFeeReceiver",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "sweep",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {INonfungiblePositionManager} from "./external/INonfungiblePositionManager.sol";
/**
* @title LP Holder
* @notice Permanently locks and collects fees from UniV3 LP positions
*/
contract LpHolder is ERC721Holder, Ownable {
using SafeERC20 for IERC20;
////////////////////////////////////////////////////////////////////////////////
// CONSTANTS AND IMMUTABLES
////////////////////////////////////////////////////////////////////////////////
INonfungiblePositionManager public immutable UNISWAP_V3_NFT_MANAGER;
////////////////////////////////////////////////////////////////////////////////
// STATE
////////////////////////////////////////////////////////////////////////////////
/// @notice Receives fees collected from UniV3 LP positions
address public feeReceiver;
////////////////////////////////////////////////////////////////////////////////
// CONSTRUCTION AND INITIALIZATION
////////////////////////////////////////////////////////////////////////////////
constructor(address _nftManager, address _feeReceiver) Ownable(msg.sender) {
if (_nftManager == address(0) || _feeReceiver == address(0))
revert LpHolder__ZeroAddress();
UNISWAP_V3_NFT_MANAGER = INonfungiblePositionManager(_nftManager);
feeReceiver = _feeReceiver;
}
////////////////////////////////////////////////////////////////////////////////
// FEE MANAGEMENT
////////////////////////////////////////////////////////////////////////////////
/**
* @notice Collect fees from UniV3 LP positions
* @param tokenIds Array of token IDs to collect fees from
*/
function collectFees(uint256[] calldata tokenIds) external {
if (tokenIds.length == 0) revert LpHolder__ZeroLength();
INonfungiblePositionManager.CollectParams
memory params = INonfungiblePositionManager.CollectParams({
tokenId: 0,
recipient: feeReceiver,
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
});
for (uint256 i; i < tokenIds.length; ) {
params.tokenId = tokenIds[i];
UNISWAP_V3_NFT_MANAGER.collect(params);
unchecked {
++i;
}
}
}
/**
* @notice Sweep tokens from the contract
* @param token Token to sweep
*/
function sweep(address token) external onlyOwner {
IERC20(token).safeTransfer(
feeReceiver,
IERC20(token).balanceOf(address(this))
);
}
////////////////////////////////////////////////////////////////////////////////
// ADMINISTRATION
////////////////////////////////////////////////////////////////////////////////
/**
* @notice Set the fee receiver
* @param _feeReceiver New fee receiver
*/
function setFeeReceiver(address _feeReceiver) external onlyOwner {
if (_feeReceiver == address(0)) revert LpHolder__ZeroAddress();
emit FeeReceiverSet(_feeReceiver, feeReceiver);
feeReceiver = _feeReceiver;
}
////////////////////////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////////////////////////
event FeeReceiverSet(address newFeeReceiver, address oldFeeReceiver);
////////////////////////////////////////////////////////////////////////////////
// ERRORS
////////////////////////////////////////////////////////////////////////////////
error LpHolder__ZeroAddress();
error LpHolder__ZeroLength();
}
Chain explorer3143msChain node77ms