Launcher
0x0578f2fb55882e18ce121014d0ef79563f5794f9
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
3,646 bytes
ABI entries
12
5 read · 1 write
License
mit
Contract information
- Address
- 0x0578f2fb55882e18ce121014d0ef79563f5794f9
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0xc53444132B…61745A3655
- Creation tx
- 0xfcd37b3aa7…fc6588e613
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (5)
lpTokenOf(address) → uint256
permit2() → address
poolManager() → address
posManager() → address
router() → address
Events (1)
LpMinted
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_pm",
"type": "address"
},
{
"internalType": "address",
"name": "_posMgr",
"type": "address"
},
{
"internalType": "address",
"name": "_router",
"type": "address"
},
{
"internalType": "address",
"name": "_permit2",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "LenMismatch",
"type": "error"
},
{
"inputs": [],
"name": "RefundFailed",
"type": "error"
},
{
"inputs": [],
"name": "ZeroSniper",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "lpTokenId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "LpMinted",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenAmount",
"type": "uint256"
},
{
"components": [
{
"internalType": "address",
"name": "currency0",
"type": "address"
},
{
"internalType": "address",
"name": "currency1",
"type": "address"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"internalType": "int24",
"name": "tickSpacing",
"type": "int24"
},
{
"internalType": "address",
"name": "hooks",
"type": "address"
}
],
"internalType": "struct PoolKey",
"name": "key",
"type": "tuple"
},
{
"internalType": "uint160",
"name": "sqrtPriceX96",
"type": "uint160"
},
{
"internalType": "bytes",
"name": "mintUnlockData",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "mintEthValue",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "buyCommands",
"type": "bytes"
},
{
"internalType": "bytes[]",
"name": "buyInputs",
"type": "bytes[]"
},
{
"internalType": "uint256[]",
"name": "buyEthValues",
"type": "uint256[]"
},
{
"internalType": "address[]",
"name": "sniperWallets",
"type": "address[]"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
}
],
"name": "atomicLaunch",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "lpTokenOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "permit2",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "poolManager",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "posManager",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "router",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
interface IERC20 {
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function balanceOf(address) external view returns (uint256);
}
library SafeT {
function safeTransfer(IERC20 t, address to, uint256 amount) internal {
(bool ok, bytes memory data) = address(t).call(
abi.encodeWithSelector(t.transfer.selector, to, amount)
);
require(ok && (data.length == 0 || abi.decode(data, (bool))), "Launcher: transfer fail");
}
function safeTransferFrom(IERC20 t, address from, address to, uint256 amount) internal {
(bool ok, bytes memory data) = address(t).call(
abi.encodeWithSelector(t.transferFrom.selector, from, to, amount)
);
require(ok && (data.length == 0 || abi.decode(data, (bool))), "Launcher: transferFrom fail");
}
function safeApprove(IERC20 t, address spender, uint256 amount) internal {
(bool ok, bytes memory data) = address(t).call(
abi.encodeWithSelector(t.approve.selector, spender, amount)
);
require(ok && (data.length == 0 || abi.decode(data, (bool))), "Launcher: approve fail");
}
}
struct PoolKey {
address currency0;
address currency1;
uint24 fee;
int24 tickSpacing;
address hooks;
}
interface IPoolManager {
function initialize(PoolKey memory key, uint160 sqrtPriceX96) external returns (int24);
}
interface IPositionManager {
function modifyLiquidities(bytes calldata unlockData, uint256 deadline) external payable;
function nextTokenId() external view returns (uint256);
}
interface IPermit2 {
function approve(address token, address spender, uint160 amount, uint48 expiration) external;
}
interface IUniversalRouter {
function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable;
}
contract Launcher {
using SafeT for IERC20;
address public immutable poolManager;
address public immutable posManager;
address public immutable router;
address public immutable permit2;
error LenMismatch();
error RefundFailed();
error ZeroSniper();
mapping(address => uint256) public lpTokenOf;
event LpMinted(address indexed token, uint256 indexed lpTokenId, address indexed recipient);
constructor(address _pm, address _posMgr, address _router, address _permit2) {
poolManager = _pm;
posManager = _posMgr;
router = _router;
permit2 = _permit2;
}
function atomicLaunch(
address token,
uint256 tokenAmount,
PoolKey calldata key,
uint160 sqrtPriceX96,
bytes calldata mintUnlockData,
uint256 mintEthValue,
bytes calldata buyCommands,
bytes[] calldata buyInputs,
uint256[] calldata buyEthValues,
address[] calldata sniperWallets,
uint256 deadline
) external payable {
if (buyInputs.length != buyEthValues.length) revert LenMismatch();
if (buyInputs.length != sniperWallets.length) revert LenMismatch();
for (uint256 j = 0; j < sniperWallets.length; ++j) {
if (sniperWallets[j] == address(0)) revert ZeroSniper();
}
IERC20(token).safeTransferFrom(msg.sender, address(this), tokenAmount);
IERC20(token).safeApprove(permit2, type(uint256).max);
IPermit2(permit2).approve(token, posManager, type(uint160).max, type(uint48).max);
IPoolManager(poolManager).initialize(key, sqrtPriceX96);
uint256 lpId = IPositionManager(posManager).nextTokenId();
IPositionManager(posManager).modifyLiquidities{value: mintEthValue}(mintUnlockData, deadline);
lpTokenOf[token] = lpId;
emit LpMinted(token, lpId, msg.sender);
uint256 n = buyInputs.length;
for (uint256 i = 0; i < n;) {
uint256 pre = IERC20(token).balanceOf(address(this));
bytes[] memory single = new bytes[](1);
single[0] = buyInputs[i];
IUniversalRouter(router).execute{value: buyEthValues[i]}(buyCommands, single, deadline);
uint256 got = IERC20(token).balanceOf(address(this)) - pre;
if (got > 0) IERC20(token).safeTransfer(sniperWallets[i], got);
unchecked { ++i; }
}
uint256 leftoverTok = IERC20(token).balanceOf(address(this));
if (leftoverTok > 0) IERC20(token).safeTransfer(msg.sender, leftoverTok);
uint256 leftover = address(this).balance;
if (leftover > 0) {
(bool ok,) = msg.sender.call{value: leftover}("");
if (!ok) revert RefundFailed();
}
}
receive() external payable {}
}
Chain explorer3679msChain node83ms