LaunchLocker
0x7f03effbd7ceb22a3f80dd468f67ef27826acd85
Verification
Verified
v0.8.30+commit.73712a01
Type
Contract
4,823 bytes
ABI entries
39
9 read · 9 write
License
none
Contract information
- Address
- 0x7f03effbd7ceb22a3f80dd468f67ef27826acd85
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.30+commit.73712a01
- Optimization
- Enabled
- Creator
- 0x7E035Fb048…b1C187242B
- Creation tx
- 0x359a038b1f…61c71695f8
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (9)
deployerTokens(address, uint256) → address
factory() → address
feeCollectors(address) → bool
feeRedirects(address) → address
getLaunchedToken(address) → tuple
onERC721Received(address, address, uint256, bytes) → bytes4
owner() → address
protocolFeeRecipient() → address
protocolFeeShare() → uint256
Events (8)
FactoryUpdatedFeeCollectorUpdatedFeeRedirectUpdatedFeesClaimedOwnershipTransferredPositionLockedProtocolFeeRecipientUpdatedProtocolFeeUpdated
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_protocolFeeRecipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "_protocolFeeShare",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AlreadyInitialized",
"type": "error"
},
{
"inputs": [],
"name": "InvalidProtocolFee",
"type": "error"
},
{
"inputs": [],
"name": "NoFeesToCollect",
"type": "error"
},
{
"inputs": [],
"name": "NotAuthorized",
"type": "error"
},
{
"inputs": [],
"name": "NotDeployer",
"type": "error"
},
{
"inputs": [],
"name": "NotFactory",
"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": [],
"name": "PositionNotHeld",
"type": "error"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [],
"name": "TokenNotFound",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newFactory",
"type": "address"
}
],
"name": "FactoryUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "collector",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "status",
"type": "bool"
}
],
"name": "FeeCollectorUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "FeeRedirectUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "caller",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "token0",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "token1",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "recipientAmount0",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "recipientAmount1",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "protocolAmount0",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "protocolAmount1",
"type": "uint256"
}
],
"name": "FeesClaimed",
"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"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "deployer",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "positionId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "pairedToken",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "dexId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "positionManager",
"type": "address"
}
],
"name": "PositionLocked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "newRecipient",
"type": "address"
}
],
"name": "ProtocolFeeRecipientUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "newFee",
"type": "uint256"
}
],
"name": "ProtocolFeeUpdated",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "collectFees",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "deployerTokens",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "feeCollectors",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "feeRedirects",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "getLaunchedToken",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "deployer",
"type": "address"
},
{
"internalType": "address",
"name": "pairedToken",
"type": "address"
},
{
"internalType": "address",
"name": "positionManager",
"type": "address"
},
{
"internalType": "uint256",
"name": "positionId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "dexId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "launchConfigId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "restrictionsEndBlock",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "supply",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isToken0",
"type": "bool"
},
{
"internalType": "uint24",
"name": "poolFee",
"type": "uint24"
},
{
"internalType": "bool",
"name": "exists",
"type": "bool"
},
{
"internalType": "uint256",
"name": "initialBuyAmount",
"type": "uint256"
}
],
"internalType": "struct LauncherTypes.LaunchedToken",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_factory",
"type": "address"
}
],
"name": "initialize",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "lockPosition",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"name": "onERC721Received",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "protocolFeeRecipient",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "protocolFeeShare",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "collector",
"type": "address"
},
{
"internalType": "bool",
"name": "status",
"type": "bool"
}
],
"name": "setFeeCollector",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "setFeeRedirect",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_protocolFeeRecipient",
"type": "address"
}
],
"name": "setProtocolFeeRecipient",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_protocolFeeShare",
"type": "uint256"
}
],
"name": "setProtocolFeeShare",
"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.30;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
library LauncherTypes {
struct LaunchedToken {
address token;
address deployer;
address pairedToken;
address positionManager;
uint256 positionId;
uint256 dexId;
uint256 launchConfigId;
uint256 restrictionsEndBlock;
uint256 supply;
bool isToken0;
uint24 poolFee;
bool exists;
uint256 initialBuyAmount;
}
}
interface ILaunchFactory {
function getLaunchedToken(address token) external view returns (LauncherTypes.LaunchedToken memory);
}
interface INonfungiblePositionManager {
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function ownerOf(uint256 tokenId) external view returns (address);
function positions(uint256 tokenId)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function collect(CollectParams calldata params) external returns (uint256 amount0, uint256 amount1);
}
contract LaunchLocker is Ownable, ReentrancyGuard, IERC721Receiver {
error AlreadyInitialized();
error InvalidProtocolFee();
error NoFeesToCollect();
error NotAuthorized();
error NotDeployer();
error NotFactory();
error PositionNotHeld();
error TokenNotFound();
error ZeroAddress();
event FactoryUpdated(address indexed newFactory);
event FeeCollectorUpdated(address indexed collector, bool status);
event FeeRedirectUpdated(address indexed token, address indexed recipient);
event FeesClaimed(
address indexed token,
address indexed caller,
address token0,
address token1,
uint256 recipientAmount0,
uint256 recipientAmount1,
uint256 protocolAmount0,
uint256 protocolAmount1
);
event PositionLocked(
address indexed token,
address indexed deployer,
uint256 positionId,
address pairedToken,
uint256 indexed dexId,
address positionManager
);
event ProtocolFeeRecipientUpdated(address newRecipient);
event ProtocolFeeUpdated(uint256 newFee);
uint256 public protocolFeeShare;
address public protocolFeeRecipient;
address public factory;
mapping(address => address[]) public deployerTokens;
mapping(address => bool) public feeCollectors;
mapping(address => address) public feeRedirects;
constructor(address _protocolFeeRecipient, uint256 _protocolFeeShare) Ownable(msg.sender) {
if (_protocolFeeRecipient == address(0)) revert ZeroAddress();
if (_protocolFeeShare > 100) revert InvalidProtocolFee();
protocolFeeRecipient = _protocolFeeRecipient;
protocolFeeShare = _protocolFeeShare;
}
function initialize(address _factory) external onlyOwner {
if (_factory == address(0)) revert ZeroAddress();
if (factory != address(0)) revert AlreadyInitialized();
factory = _factory;
emit FactoryUpdated(_factory);
}
function getLaunchedToken(address token) public view returns (LauncherTypes.LaunchedToken memory) {
return ILaunchFactory(factory).getLaunchedToken(token);
}
function onERC721Received(address, address from, uint256, bytes calldata)
external
view
override
returns (bytes4)
{
if (from != factory) revert NotFactory();
return IERC721Receiver.onERC721Received.selector;
}
function lockPosition(address token) external {
if (msg.sender != factory) revert NotFactory();
LauncherTypes.LaunchedToken memory launched = ILaunchFactory(factory).getLaunchedToken(token);
if (!launched.exists || launched.token == address(0)) revert TokenNotFound();
if (
launched.deployer == address(0) || launched.pairedToken == address(0)
|| launched.positionManager == address(0) || launched.token != token
) revert TokenNotFound();
if (INonfungiblePositionManager(launched.positionManager).ownerOf(launched.positionId) != address(this)) {
revert PositionNotHeld();
}
deployerTokens[launched.deployer].push(token);
emit PositionLocked(
token,
launched.deployer,
launched.positionId,
launched.pairedToken,
launched.dexId,
launched.positionManager
);
}
function collectFees(address token) external nonReentrant {
LauncherTypes.LaunchedToken memory launched = ILaunchFactory(factory).getLaunchedToken(token);
if (!launched.exists) revert TokenNotFound();
if (msg.sender != owner() && msg.sender != launched.deployer && !feeCollectors[msg.sender]) {
revert NotAuthorized();
}
INonfungiblePositionManager manager = INonfungiblePositionManager(launched.positionManager);
(uint256 amount0, uint256 amount1) = manager.collect(
INonfungiblePositionManager.CollectParams({
tokenId: launched.positionId,
recipient: address(this),
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
if (amount0 == 0 && amount1 == 0) revert NoFeesToCollect();
(,, address token0, address token1,,,,,,,,) = manager.positions(launched.positionId);
uint256 protocolAmount0 = (amount0 * protocolFeeShare) / 100;
uint256 protocolAmount1 = (amount1 * protocolFeeShare) / 100;
uint256 recipientAmount0 = amount0 - protocolAmount0;
uint256 recipientAmount1 = amount1 - protocolAmount1;
address recipient = feeRedirects[token] != address(0) ? feeRedirects[token] : launched.deployer;
if (amount0 != 0) {
IERC20(token0).transfer(protocolFeeRecipient, protocolAmount0);
IERC20(token0).transfer(recipient, recipientAmount0);
}
if (amount1 != 0) {
IERC20(token1).transfer(protocolFeeRecipient, protocolAmount1);
IERC20(token1).transfer(recipient, recipientAmount1);
}
emit FeesClaimed(
token,
msg.sender,
token0,
token1,
recipientAmount0,
recipientAmount1,
protocolAmount0,
protocolAmount1
);
}
function setFeeRedirect(address token, address recipient) external {
LauncherTypes.LaunchedToken memory launched = ILaunchFactory(factory).getLaunchedToken(token);
if (!launched.exists) revert TokenNotFound();
if (msg.sender != launched.deployer) revert NotDeployer();
feeRedirects[token] = recipient;
emit FeeRedirectUpdated(token, recipient);
}
function setFeeCollector(address collector, bool status) external onlyOwner {
if (collector == address(0)) revert ZeroAddress();
feeCollectors[collector] = status;
emit FeeCollectorUpdated(collector, status);
}
function setProtocolFeeShare(uint256 _protocolFeeShare) external onlyOwner {
if (_protocolFeeShare > 100) revert InvalidProtocolFee();
protocolFeeShare = _protocolFeeShare;
emit ProtocolFeeUpdated(_protocolFeeShare);
}
function setProtocolFeeRecipient(address _protocolFeeRecipient) external onlyOwner {
if (_protocolFeeRecipient == address(0)) revert ZeroAddress();
protocolFeeRecipient = _protocolFeeRecipient;
emit ProtocolFeeRecipientUpdated(_protocolFeeRecipient);
}
}
Chain explorer3322msChain node82ms