UniLaunchPad
0xc9c85b08354dfb2a760ab3042a7d9b86ba98197e
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
7,315 bytes
ABI entries
31
11 read · 5 write
License
none
Contract information
- Address
- 0xc9c85b08354dfb2a760ab3042a7d9b86ba98197e
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x6Cc6F33A58…7a784dB737
- Creation tx
- 0x1e7a8e531c…449a63c56e
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (11)
POOL_FEE() → uint24
TOTAL_SUPPLY() → uint256
creatorOf(address) → address
graduator() → address
locker() → address
owner() → address
poolOf(address) → address
positionManager() → address
tokenImplementation() → address
v3Factory() → address
weth() → address
Events (5)
GraduatorUpdatedLaunchedLockerSetOwnerUpdatedTokenCreated
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "weth_",
"type": "address"
},
{
"internalType": "address",
"name": "v3Factory_",
"type": "address"
},
{
"internalType": "address",
"name": "positionManager_",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "BadCallback",
"type": "error"
},
{
"inputs": [],
"name": "BadValue",
"type": "error"
},
{
"inputs": [],
"name": "LockerAlreadySet",
"type": "error"
},
{
"inputs": [],
"name": "LockerNotSet",
"type": "error"
},
{
"inputs": [],
"name": "NotOwner",
"type": "error"
},
{
"inputs": [],
"name": "PoolExists",
"type": "error"
},
{
"inputs": [],
"name": "Reentrancy",
"type": "error"
},
{
"inputs": [],
"name": "SlippageExceeded",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "graduator",
"type": "address"
}
],
"name": "GraduatorUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "positionId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "initialBuyEth",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "initialTokensOut",
"type": "uint256"
}
],
"name": "Launched",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "locker",
"type": "address"
}
],
"name": "LockerSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnerUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"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"
}
],
"name": "TokenCreated",
"type": "event"
},
{
"inputs": [],
"name": "POOL_FEE",
"outputs": [
{
"internalType": "uint24",
"name": "",
"type": "uint24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TOTAL_SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
},
{
"internalType": "string",
"name": "imageURI",
"type": "string"
},
{
"internalType": "uint256",
"name": "minInitialTokensOut",
"type": "uint256"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
}
],
"name": "create",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "creatorOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "graduator",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "locker",
"outputs": [
{
"internalType": "contract LpLocker",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"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": "contract INonfungiblePositionManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "graduator_",
"type": "address"
}
],
"name": "setGraduator",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "locker_",
"type": "address"
}
],
"name": "setLocker",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "setOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "tokenImplementation",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "int256",
"name": "amount0Delta",
"type": "int256"
},
{
"internalType": "int256",
"name": "amount1Delta",
"type": "int256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "uniswapV3SwapCallback",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "v3Factory",
"outputs": [
{
"internalType": "contract IUniswapV3Factory",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "weth",
"outputs": [
{
"internalType": "contract IWETH9",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {UniPadToken} from "./UniPadToken.sol";
import {LpLocker} from "./LpLocker.sol";
import {
IUniswapV3Factory,
IUniswapV3Pool,
INonfungiblePositionManager,
IWETH9
} from "./interfaces/IUniswapV3.sol";
contract UniLaunchPad {
uint256 public constant TOTAL_SUPPLY = 1_000_000_000e18;
uint24 public constant POOL_FEE = 10_000;
int24 internal constant START_TICK = 204_200;
int24 internal constant MIN_TICK = -887_200;
int24 internal constant MAX_TICK = 887_200;
uint160 internal constant SQRT_PRICE_NEG_START = 2917122157712197017744680;
uint160 internal constant SQRT_PRICE_POS_START = 2151813121295408910812139624586144;
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
address public immutable tokenImplementation;
IWETH9 public immutable weth;
IUniswapV3Factory public immutable v3Factory;
INonfungiblePositionManager public immutable positionManager;
address public owner;
LpLocker public locker;
address public graduator;
mapping(address => address) public poolOf;
mapping(address => address) public creatorOf;
address private expectedPool;
uint256 private locked = 1;
event TokenCreated(
address indexed token,
address indexed creator,
string name,
string symbol,
string metadataURI
);
event Launched(
address indexed token,
address indexed pool,
uint256 indexed positionId,
address creator,
uint256 initialBuyEth,
uint256 initialTokensOut
);
event OwnerUpdated(address owner);
event LockerSet(address locker);
event GraduatorUpdated(address graduator);
error NotOwner();
error LockerAlreadySet();
error LockerNotSet();
error BadValue();
error PoolExists();
error SlippageExceeded();
error Reentrancy();
error BadCallback();
constructor(address weth_, address v3Factory_, address positionManager_) {
tokenImplementation = address(new UniPadToken());
weth = IWETH9(weth_);
v3Factory = IUniswapV3Factory(v3Factory_);
positionManager = INonfungiblePositionManager(positionManager_);
owner = msg.sender;
}
modifier nonReentrant() {
if (locked != 1) revert Reentrancy();
locked = 2;
_;
locked = 1;
}
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
function setLocker(address locker_) external onlyOwner {
if (address(locker) != address(0)) revert LockerAlreadySet();
locker = LpLocker(locker_);
emit LockerSet(locker_);
}
function setOwner(address newOwner) external onlyOwner {
owner = newOwner;
emit OwnerUpdated(newOwner);
}
function setGraduator(address graduator_) external onlyOwner {
graduator = graduator_;
emit GraduatorUpdated(graduator_);
}
function create(
string calldata name,
string calldata symbol,
string calldata metadataURI,
string calldata imageURI,
uint256 minInitialTokensOut,
bytes32 salt
) external payable nonReentrant returns (address token) {
if (address(locker) == address(0)) revert LockerNotSet();
token = _cloneDeterministic(tokenImplementation, keccak256(abi.encodePacked(msg.sender, salt)));
UniPadToken(token).initialize(name, symbol, TOTAL_SUPPLY, metadataURI, imageURI);
bool tokenIs0 = token < address(weth);
(address token0, address token1) = tokenIs0 ? (token, address(weth)) : (address(weth), token);
uint160 initSqrt = tokenIs0 ? SQRT_PRICE_NEG_START : SQRT_PRICE_POS_START;
int24 tickLower = tokenIs0 ? -START_TICK : MIN_TICK;
int24 tickUpper = tokenIs0 ? MAX_TICK : START_TICK;
if (v3Factory.getPool(token0, token1, POOL_FEE) != address(0)) revert PoolExists();
address pool = positionManager.createAndInitializePoolIfNecessary(token0, token1, POOL_FEE, initSqrt);
poolOf[token] = pool;
creatorOf[token] = msg.sender;
(uint160 sqrtP,,,,,,) = IUniswapV3Pool(pool).slot0();
if (sqrtP != initSqrt) revert PoolExists();
UniPadToken(token).setTradeConfig(pool, msg.sender, address(locker));
UniPadToken(token).approve(address(positionManager), TOTAL_SUPPLY);
(uint256 tokenId,,,) = positionManager.mint(
INonfungiblePositionManager.MintParams({
token0: token0,
token1: token1,
fee: POOL_FEE,
tickLower: tickLower,
tickUpper: tickUpper,
amount0Desired: tokenIs0 ? TOTAL_SUPPLY : 0,
amount1Desired: tokenIs0 ? 0 : TOTAL_SUPPLY,
amount0Min: 0,
amount1Min: 0,
recipient: address(locker),
deadline: block.timestamp
})
);
UniPadToken(token).approve(address(positionManager), 0);
locker.register(tokenId, msg.sender);
uint256 dust = UniPadToken(token).balanceOf(address(this));
if (dust > 0) UniPadToken(token).transfer(address(0xdead), dust);
emit TokenCreated(token, msg.sender, name, symbol, metadataURI);
uint256 tokensOut = 0;
if (msg.value > 0) {
tokensOut = _initialBuy(token, pool, tokenIs0, msg.value, minInitialTokensOut, msg.sender);
}
emit Launched(token, pool, tokenId, msg.sender, msg.value, tokensOut);
}
function _initialBuy(
address token,
address pool,
bool tokenIs0,
uint256 ethIn,
uint256 minOut,
address recipient
) internal returns (uint256 tokensOut) {
weth.deposit{value: ethIn}();
bool zeroForOne = !tokenIs0;
uint160 limit = zeroForOne ? MIN_SQRT_RATIO + 1 : MAX_SQRT_RATIO - 1;
expectedPool = pool;
(int256 a0, int256 a1) = IUniswapV3Pool(pool).swap(
recipient, zeroForOne, int256(ethIn), limit, abi.encode(token, tokenIs0)
);
expectedPool = address(0);
tokensOut = tokenIs0 ? uint256(-a0) : uint256(-a1);
if (tokensOut < minOut) revert SlippageExceeded();
}
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external {
if (msg.sender != expectedPool || expectedPool == address(0)) revert BadCallback();
(address token, bool tokenIs0) = abi.decode(data, (address, bool));
if (amount0Delta > 0) {
if (tokenIs0) UniPadToken(token).transfer(msg.sender, uint256(amount0Delta));
else weth.transfer(msg.sender, uint256(amount0Delta));
}
if (amount1Delta > 0) {
if (tokenIs0) weth.transfer(msg.sender, uint256(amount1Delta));
else UniPadToken(token).transfer(msg.sender, uint256(amount1Delta));
}
}
function _cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
bytes memory bytecode = abi.encodePacked(
hex"3d602d80600a3d3981f3363d3d373d3d3d363d73",
implementation,
hex"5af43d82803e903d91602b57fd5bf3"
);
/// @solidity memory-safe-assembly
assembly {
instance := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
}
if (instance == address(0)) revert BadValue();
}
receive() external payable {
if (msg.sender != address(weth)) revert BadValue();
}
}
Chain explorer2935msChain node80ms