LaunchpadLoot
0x984a1306c5a9bfaafa0bbbfda451a473ad3dcfd9
Verification
Verified
v0.8.25+commit.b61c2a91
Type
Contract
15,502 bytes
ABI entries
29
19 read · 7 write
License
none
Contract information
- Address
- 0x984a1306c5a9bfaafa0bbbfda451a473ad3dcfd9
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.25+commit.b61c2a91
- Optimization
- Enabled
- Creator
- 0x95D7768738…faBF8699D5
- Creation tx
- 0xe7f0d8cb09…cee298e74c
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (19)
SUPPLY() → uint256
allLaunches() → tuple[]
createFeeWei() → uint256
domainSeparator() → bytes32
fee() → uint24
launchAt(uint256) → tuple
launchCount() → uint256
launches(uint256) → address, address, address, string, string, string, uint64, uint256
locker() → address
nonces(address) → uint256
owner() → address
platform() → address
poolOf(address) → address
positionManager() → address
sqrtPriceX96() → uint160
swapRouter() → address
tickLower() → int24
tickUpper() → int24
weth() → address
Events (1)
Launched
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "positionManager_",
"type": "address"
},
{
"internalType": "address",
"name": "swapRouter_",
"type": "address"
},
{
"internalType": "address",
"name": "weth_",
"type": "address"
},
{
"internalType": "address",
"name": "locker_",
"type": "address"
},
{
"internalType": "address",
"name": "platform_",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "string",
"name": "name",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "metadataURI",
"type": "string"
},
{
"indexed": false,
"internalType": "uint256",
"name": "lpTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "devBuyTokens",
"type": "uint256"
}
],
"name": "Launched",
"type": "event"
},
{
"inputs": [],
"name": "SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "allLaunches",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
},
{
"internalType": "uint64",
"name": "createdAt",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "lpTokenId",
"type": "uint256"
}
],
"internalType": "struct LaunchpadLoot.Launch[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "createFeeWei",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
},
{
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "signature",
"type": "bytes"
}
],
"name": "createFor",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "domainSeparator",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "fee",
"outputs": [
{
"internalType": "uint24",
"name": "",
"type": "uint24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
}
],
"name": "launch",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "i",
"type": "uint256"
}
],
"name": "launchAt",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
},
{
"internalType": "uint64",
"name": "createdAt",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "lpTokenId",
"type": "uint256"
}
],
"internalType": "struct LaunchpadLoot.Launch",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launchCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "launches",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
},
{
"internalType": "uint64",
"name": "createdAt",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "lpTokenId",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "locker",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "nonces",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "platform",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "poolOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "positionManager",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
}
],
"name": "rescueETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "wei_",
"type": "uint256"
}
],
"name": "setCreateFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "p",
"type": "address"
}
],
"name": "setPlatform",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint160",
"name": "sqrtPriceX96_",
"type": "uint160"
},
{
"internalType": "int24",
"name": "tickLower_",
"type": "int24"
},
{
"internalType": "int24",
"name": "tickUpper_",
"type": "int24"
},
{
"internalType": "uint24",
"name": "fee_",
"type": "uint24"
}
],
"name": "setSeedParams",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "sqrtPriceX96",
"outputs": [
{
"internalType": "uint160",
"name": "",
"type": "uint160"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "swapRouter",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tickLower",
"outputs": [
{
"internalType": "int24",
"name": "",
"type": "int24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tickUpper",
"outputs": [
{
"internalType": "int24",
"name": "",
"type": "int24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "n",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "weth",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
//
// =========================================================
// ____ __ _ __ __
// / __ \____ / /_ (_)___ / / ____ ____ / /_
// / /_/ / __ \/ __ \/ / __ \ / / / __ \/ __ \/ __/
// / _, _/ /_/ / /_/ / / / / / / /___/ /_/ / /_/ / /_
// /_/ |_|\____/_.___/_/_/ /_/ /_____/\____/\____/\__/
// =========================================================
//
pragma solidity ^0.8.25;
import { LaunchToken } from "./LaunchToken.sol";
import {
INonfungiblePositionManager,
SwapCompat,
IWETH9,
IERC20Min,
ILootLocker
} from "./RobinLootInterfaces.sol";
/**
* @title LaunchpadLoot
* @notice One-tx mint + launch of a fixed-supply, admin-less LaunchToken straight
* into a locked single-sided Uniswap V3 position — no bonding curve, no
* graduation. The token is a real, tradeable pool from block one, so
* Uniswap routers and DexScreener charts work natively.
*
* All 1,000,000 supply is provided as token-only liquidity in a wide range
* whose upper bound sits just below the start price, so the position is
* 100% token (zero WETH) and buys walk the price up the range.
*
* Token/WETH ordering: we deploy each LaunchToken via CREATE2 and search for
* a salt whose resulting address sorts ABOVE WETH, so token0 = WETH and
* token1 = the LaunchToken for every launch. That lets one pinned
* sqrtPriceX96 + tick range give an identical starting market cap to every
* token (ETH-pinned).
*
* launch() flow (one tx):
* 1. CREATE2-deploy a LaunchToken (full 1M minted to this factory,
* no owner/mint/pause — born immutable).
* 2. create+init the 1% V3 pool at the pinned price.
* 3. mint the single-sided position to the LootLocker (locked forever).
* 4. register the lock with the creator as fee beneficiary.
* 5. optional dev-buy: swap the creator's ETH → token on the same pool.
*
* No per-trade fee — trading happens natively on Uniswap.
*/
contract LaunchpadLoot {
address public owner;
address public immutable positionManager;
address public immutable swapRouter;
address public immutable weth;
address public immutable locker;
address public platform; // create-fee sink (fee is 0 by default)
uint256 public constant SUPPLY = 1_000_000e18;
// ---- pinned single-sided seed params (owner-configurable for FUTURE launches;
// existing pools are immutable real Uniswap pools) ----
uint24 public fee = 10_000; // 1%
int24 public tickLower = -887_200; // wide floor
int24 public tickUpper = 131_200; // just below start tick
uint160 public sqrtPriceX96 = 56022770974786141989122762342400; // ~$5k MC, ETH-pinned
uint256 public createFeeWei = 0; // free to launch
struct Launch {
address token;
address pool;
address creator;
string name;
string symbol;
string metadataURI;
uint64 createdAt;
uint256 lpTokenId;
}
Launch[] public launches;
mapping(address => address) public poolOf; // token => pool
uint256 public launchCount;
// EIP-712 gasless launches.
mapping(address => uint256) public nonces;
bytes32 private constant _EIP712_DOMAIN_TYPEHASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 private constant _LAUNCH_TYPEHASH =
keccak256("Launch(address creator,string name,string symbol,string metadataURI,uint256 nonce,uint256 deadline)");
bytes32 private constant _NAME_HASH = keccak256(bytes("RobinLootLaunchpad"));
bytes32 private constant _VERSION_HASH = keccak256(bytes("1"));
bool private _entered;
modifier nonReentrant() { require(!_entered, "re"); _entered = true; _; _entered = false; }
modifier onlyOwner() { require(msg.sender == owner, "o"); _; }
event Launched(
address indexed token,
address indexed pool,
address indexed creator,
string name,
string symbol,
string metadataURI,
uint256 lpTokenId,
uint256 devBuyTokens
);
constructor(address positionManager_, address swapRouter_, address weth_, address locker_, address platform_) {
require(
positionManager_ != address(0) && swapRouter_ != address(0) &&
weth_ != address(0) && locker_ != address(0) && platform_ != address(0),
"zero"
);
owner = msg.sender;
positionManager = positionManager_;
swapRouter = swapRouter_;
weth = weth_;
locker = locker_;
platform = platform_;
}
/// Launch a token. Caller is the creator; msg.value beyond createFeeWei is an
/// optional dev-buy executed as a normal swap against the fresh pool.
function launch(string calldata name, string calldata symbol, string calldata metadataURI)
external
payable
nonReentrant
returns (address token, address pool)
{
return _launch(msg.sender, name, symbol, metadataURI, msg.value);
}
/// Gasless launch for ANY wallet: `creator` signs an EIP-712 Launch request
/// off-chain and a relayer submits it here and pays gas. No dev-buy on this
/// path (it would need the creator's ETH). The token is credited to `creator`.
function createFor(
address creator,
string calldata name,
string calldata symbol,
string calldata metadataURI,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) external nonReentrant returns (address token, address pool) {
require(block.timestamp <= deadline, "expired");
require(nonce == nonces[creator], "nonce");
_verifyLaunchSig(creator, name, symbol, metadataURI, nonce, deadline, signature);
nonces[creator] = nonce + 1;
return _launch(creator, name, symbol, metadataURI, 0);
}
function _launch(
address creator,
string calldata name,
string calldata symbol,
string calldata metadataURI,
uint256 valueIn
) internal returns (address token, address pool) {
require(valueIn >= createFeeWei, "fee");
token = _deployToken(creator, name, symbol);
uint256 lpTokenId;
(pool, lpTokenId) = _seed(token, creator);
if (createFeeWei > 0) {
(bool ok, ) = platform.call{value: createFeeWei}("");
require(ok, "fee-send");
}
uint256 devBuyTokens;
uint256 devWei = valueIn - createFeeWei;
if (devWei > 0) devBuyTokens = _devBuy(token, creator, devWei);
_register(token, pool, creator, name, symbol, metadataURI, lpTokenId, devBuyTokens);
}
/// Born-renounced, fixed-supply LaunchToken: full 1M minted to THIS factory,
/// no owner, no mint, no pause. CREATE2-deployed with a salt chosen so the
/// token address sorts above WETH → token0 = WETH always.
function _deployToken(address creator, string calldata name, string calldata symbol)
internal
returns (address token)
{
bytes memory initCode = abi.encodePacked(
type(LaunchToken).creationCode,
abi.encode(name, symbol, SUPPLY, address(this))
);
bytes32 initHash = keccak256(initCode);
bytes32 salt = keccak256(abi.encode(creator, launchCount));
// Bump the salt until the predicted CREATE2 address sorts above WETH.
while (uint160(_create2Address(salt, initHash)) <= uint160(weth)) {
salt = keccak256(abi.encodePacked(salt));
}
token = address(new LaunchToken{salt: salt}(name, symbol, SUPPLY, address(this)));
// Invariant: token > WETH → token0 = WETH always.
require(uint160(token) > uint160(weth), "order");
require(IERC20Min(token).balanceOf(address(this)) == SUPPLY, "mint");
}
/// EIP-1014 CREATE2 address prediction for a given salt + init-code hash.
function _create2Address(bytes32 salt, bytes32 initHash) internal view returns (address) {
return address(uint160(uint256(
keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, initHash))
)));
}
/// Seed the single-sided position (all token1, zero WETH) into the locker.
function _seed(address token, address creator) internal returns (address pool, uint256 lpTokenId) {
require(IERC20Min(token).approve(positionManager, SUPPLY), "approve");
pool = INonfungiblePositionManager(positionManager).createAndInitializePoolIfNecessary(
weth, token, fee, sqrtPriceX96
);
(lpTokenId, , , ) = INonfungiblePositionManager(positionManager).mint(
INonfungiblePositionManager.MintParams({
token0: weth,
token1: token,
fee: fee,
tickLower: tickLower,
tickUpper: tickUpper,
amount0Desired: 0,
amount1Desired: SUPPLY,
amount0Min: 0,
amount1Min: 0,
recipient: locker,
deadline: block.timestamp
})
);
ILootLocker(locker).register(lpTokenId, creator);
poolOf[token] = pool;
}
/// Optional launch dev-buy: wrap ETH and swap WETH→token on the new pool,
/// delivering the bought tokens straight to the creator.
function _devBuy(address token, address creator, uint256 wei_) internal returns (uint256 out) {
IWETH9(weth).deposit{value: wei_}();
require(IWETH9(weth).approve(swapRouter, wei_), "approve-weth");
// exactInputSingle via the SwapRouter variant this chain runs (with/without deadline).
out = SwapCompat.exactInputSingle(swapRouter, weth, token, fee, creator, wei_, 0);
}
function _register(
address token,
address pool,
address creator,
string calldata name,
string calldata symbol,
string calldata metadataURI,
uint256 lpTokenId,
uint256 devBuyTokens
) internal {
launches.push(Launch({
token: token,
pool: pool,
creator: creator,
name: name,
symbol: symbol,
metadataURI: metadataURI,
createdAt: uint64(block.timestamp),
lpTokenId: lpTokenId
}));
launchCount++;
emit Launched(token, pool, creator, name, symbol, metadataURI, lpTokenId, devBuyTokens);
}
// ---- EIP-712 (gasless createFor) ----
function domainSeparator() public view returns (bytes32) {
return keccak256(abi.encode(_EIP712_DOMAIN_TYPEHASH, _NAME_HASH, _VERSION_HASH, block.chainid, address(this)));
}
function _verifyLaunchSig(
address creator,
string calldata name,
string calldata symbol,
string calldata metadataURI,
uint256 nonce,
uint256 deadline,
bytes calldata sig
) internal view {
bytes32 structHash = keccak256(abi.encode(
_LAUNCH_TYPEHASH, creator,
keccak256(bytes(name)), keccak256(bytes(symbol)), keccak256(bytes(metadataURI)),
nonce, deadline
));
bytes32 digest = keccak256(abi.encodePacked(bytes2(0x1901), domainSeparator(), structHash));
require(sig.length == 65, "siglen");
bytes32 r = bytes32(sig[0:32]);
bytes32 s = bytes32(sig[32:64]);
uint8 v = uint8(sig[64]);
address signer = ecrecover(digest, v, r, s);
require(signer != address(0) && signer == creator, "sig");
}
// ---- views ----
function allLaunches() external view returns (Launch[] memory) { return launches; }
function launchAt(uint256 i) external view returns (Launch memory) { return launches[i]; }
// ---- admin ----
function setCreateFee(uint256 wei_) external onlyOwner { createFeeWei = wei_; }
function setSeedParams(uint160 sqrtPriceX96_, int24 tickLower_, int24 tickUpper_, uint24 fee_) external onlyOwner {
require(tickLower_ < tickUpper_, "ticks");
sqrtPriceX96 = sqrtPriceX96_;
tickLower = tickLower_;
tickUpper = tickUpper_;
fee = fee_;
}
function setPlatform(address p) external onlyOwner { require(p != address(0), "zero"); platform = p; }
function transferOwnership(address n) external onlyOwner { require(n != address(0), "zero"); owner = n; }
/// Sweep any ETH stuck here (launch() forwards all msg.value; dust only).
function rescueETH(address to) external onlyOwner {
require(to != address(0), "zero");
(bool ok, ) = to.call{value: address(this).balance}("");
require(ok, "send");
}
receive() external payable {}
}
Chain explorer6364msChain node94ms