Hoodlab
0xd3edd6a2ea86371ce0915458f4af100a5867920b
Verification
Verified
0.8.24+commit.e11b9ed9
Type
Contract
11,899 bytes
ABI entries
23
12 read · 3 write
License
none
Contract information
- Address
- 0xd3edd6a2ea86371ce0915458f4af100a5867920b
- Chain
- Robinhood Chain (4663)
- Compiler
- 0.8.24+commit.e11b9ed9
- Optimization
- Enabled
- Creator
- 0xF281d57a3F…003516EcA6
- Creation tx
- 0xf4ac3ea115…b449321945
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (12)
MAX_DEV_ALLOC_BPS() → uint16
MAX_VIRTUAL_ETH() → uint256
MIN_VIRTUAL_ETH() → uint256
PROTOCOL_FEE_BPS() → uint256
getLaunch(address) → tuple
launches(uint256) → address, address, address, uint256, uint256, uint256, uint24, uint40, uint8, uint16, uint16, uint16, string
launchesCount() → uint256
positionManager() → address
protocolFeeRecipient() → address
swapRouter() → address
tokenDeployer() → address
weth() → address
Events (4)
FeesClaimedFirstBuyProtocolFeeRecipientChangedTokenLaunched
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_positionManager",
"type": "address"
},
{
"internalType": "address",
"name": "_swapRouter",
"type": "address"
},
{
"internalType": "address",
"name": "_tokenDeployer",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "R",
"type": "error"
},
{
"inputs": [],
"name": "T",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "creatorEth",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "creatorTokens",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "protocolEth",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "protocolTokens",
"type": "uint256"
}
],
"name": "FeesClaimed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethIn",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokensOut",
"type": "uint256"
}
],
"name": "FirstBuy",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "oldRecipient",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newRecipient",
"type": "address"
}
],
"name": "ProtocolFeeRecipientChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "positionId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "supply",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "virtualEth",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"indexed": false,
"internalType": "uint8",
"name": "tokenType",
"type": "uint8"
},
{
"indexed": false,
"internalType": "uint16",
"name": "buyTaxBps",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint16",
"name": "sellTaxBps",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint16",
"name": "devAllocBps",
"type": "uint16"
},
{
"indexed": false,
"internalType": "address",
"name": "taxRecipient",
"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": "TokenLaunched",
"type": "event"
},
{
"inputs": [],
"name": "MAX_DEV_ALLOC_BPS",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_VIRTUAL_ETH",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MIN_VIRTUAL_ETH",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "PROTOCOL_FEE_BPS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "claimFees",
"outputs": [
{
"internalType": "uint256",
"name": "creatorEth",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "creatorTokens",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "getLaunch",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "uint256",
"name": "positionId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "supply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "virtualEth",
"type": "uint256"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"internalType": "uint40",
"name": "launchedAt",
"type": "uint40"
},
{
"internalType": "uint8",
"name": "tokenType",
"type": "uint8"
},
{
"internalType": "uint16",
"name": "buyTaxBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "sellTaxBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "devAllocBps",
"type": "uint16"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
}
],
"internalType": "struct Hoodlab.LaunchInfo",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "uint256",
"name": "supply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "virtualEth",
"type": "uint256"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"internalType": "uint8",
"name": "tokenType",
"type": "uint8"
},
{
"internalType": "uint16",
"name": "buyTaxBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "sellTaxBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "devAllocBps",
"type": "uint16"
},
{
"internalType": "address",
"name": "taxRecipient",
"type": "address"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
}
],
"name": "launch",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "uint256",
"name": "positionId",
"type": "uint256"
}
],
"stateMutability": "payable",
"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": "uint256",
"name": "positionId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "supply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "virtualEth",
"type": "uint256"
},
{
"internalType": "uint24",
"name": "fee",
"type": "uint24"
},
{
"internalType": "uint40",
"name": "launchedAt",
"type": "uint40"
},
{
"internalType": "uint8",
"name": "tokenType",
"type": "uint8"
},
{
"internalType": "uint16",
"name": "buyTaxBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "sellTaxBps",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "devAllocBps",
"type": "uint16"
},
{
"internalType": "string",
"name": "metadataURI",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launchesCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "positionManager",
"outputs": [
{
"internalType": "contract INonfungiblePositionManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "protocolFeeRecipient",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newRecipient",
"type": "address"
}
],
"name": "setProtocolFeeRecipient",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "swapRouter",
"outputs": [
{
"internalType": "contract ISwapRouter02",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tokenDeployer",
"outputs": [
{
"internalType": "contract ITokenDeployer",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"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.24;
interface ITokenDeployer {
function deployToken(
uint8 tokenType,
string calldata name,
string calldata symbol,
uint256 supply,
address supplyRecipient,
address creator,
uint16 buyTaxBps,
uint16 sellTaxBps,
address taxRecipient,
string calldata socials
) external returns (address token);
}
interface ITaxableToken {
function setPool(address pool) external;
}
import {TickMath} from "./lib/TickMath.sol";
import {FullMath} from "./lib/FullMath.sol";
import {
INonfungiblePositionManager,
ISwapRouter02,
IWETH9,
IERC20Minimal
} from "./interfaces/IUniswapV3.sol";
/// @title Hoodlab — one-sided Uniswap v3 memecoin launcher for Robinhood Chain (hoodlab.fun)
/// @notice Launches a fixed-supply ERC-20 and locks 100% of it into a single-sided
/// Uniswap v3 position. The creator deposits ZERO ETH: the starting price is
/// set from a "virtual ETH" figure (price = virtualEth / supply), i.e. the pool
/// is initialized as if it held that much ETH, without any real ETH inside.
/// Buyers supply the real ETH as they swap in; the LP position is locked in
/// this contract forever. Creators can only claim accrued swap fees.
contract Hoodlab {
INonfungiblePositionManager public immutable positionManager;
ISwapRouter02 public immutable swapRouter;
ITokenDeployer public immutable tokenDeployer;
address public immutable weth;
struct LaunchInfo {
address token;
address pool;
address creator;
uint256 positionId;
uint256 supply;
uint256 virtualEth;
uint24 fee;
uint40 launchedAt;
uint8 tokenType; // 0 = fair, 1 = tax (creator earns), 2 = reward (holders earn)
uint16 buyTaxBps;
uint16 sellTaxBps;
uint16 devAllocBps; // share of supply the creator kept in their wallet (rest locked as LP)
string metadataURI; // JSON: description + socials (x, tg, web) if provided
}
LaunchInfo[] public launches;
/// @dev token address => index in `launches` + 1 (0 = unknown token)
mapping(address => uint256) private launchIndexPlusOne;
uint256 private constant UNLOCKED = 1;
uint256 private constant LOCKED = 2;
uint256 private reentrancyLock = UNLOCKED;
uint256 public constant MIN_VIRTUAL_ETH = 0.01 ether;
uint256 public constant MAX_VIRTUAL_ETH = 1_000_000 ether;
/// @notice Largest share of supply a creator can keep in their own wallet at launch.
/// The rest is locked as LP forever. A constant cap so at least half of every
/// token's supply is always locked liquidity.
uint16 public constant MAX_DEV_ALLOC_BPS = 5000; // 50%
/// @notice Share of claimed swap fees that funds app marketing & maintenance.
/// A constant: nobody can raise it after deployment. Creators keep 70%.
uint256 public constant PROTOCOL_FEE_BPS = 3000; // 30%
/// @notice Receives the protocol share of claimed fees (initially the deployer).
address public protocolFeeRecipient;
event ProtocolFeeRecipientChanged(address indexed oldRecipient, address indexed newRecipient);
/// @notice Creator bought in with real ETH in the same transaction as the launch.
event FirstBuy(address indexed token, address indexed creator, uint256 ethIn, uint256 tokensOut);
event TokenLaunched(
address indexed token,
address indexed creator,
address pool,
uint256 positionId,
uint256 supply,
uint256 virtualEth,
uint24 fee,
uint8 tokenType,
uint16 buyTaxBps,
uint16 sellTaxBps,
uint16 devAllocBps,
address taxRecipient,
string name,
string symbol,
string metadataURI
);
event FeesClaimed(
address indexed token,
address indexed creator,
address recipient,
uint256 creatorEth,
uint256 creatorTokens,
uint256 protocolEth,
uint256 protocolTokens
);
modifier nonReentrant() {
require(reentrancyLock == UNLOCKED, "reentrancy");
reentrancyLock = LOCKED;
_;
reentrancyLock = UNLOCKED;
}
constructor(address _positionManager, address _swapRouter, address _tokenDeployer) {
positionManager = INonfungiblePositionManager(_positionManager);
swapRouter = ISwapRouter02(_swapRouter);
tokenDeployer = ITokenDeployer(_tokenDeployer);
weth = INonfungiblePositionManager(_positionManager).WETH9();
protocolFeeRecipient = msg.sender;
}
/// @notice Move the protocol fee destination (only the current recipient can).
function setProtocolFeeRecipient(address newRecipient) external {
require(msg.sender == protocolFeeRecipient, "not protocol recipient");
require(newRecipient != address(0), "zero recipient");
emit ProtocolFeeRecipientChanged(protocolFeeRecipient, newRecipient);
protocolFeeRecipient = newRecipient;
}
/// @notice Deploy a token and lock its entire supply into a one-sided v3 position.
/// @param name ERC-20 name
/// @param symbol ERC-20 symbol
/// @param supply total supply in base units (18 decimals)
/// @param virtualEth starting-price setting in wei: initial price = virtualEth / supply.
/// Purely virtual — no ETH is pulled from the caller.
/// @param fee Uniswap v3 fee tier: 500, 3000 or 10000
/// @param devAllocBps share of supply (in bps, max MAX_DEV_ALLOC_BPS) sent to the creator's
/// wallet at launch; the remainder is locked as LP. 0 = lock everything.
/// @param taxRecipient wallet that receives the creator's 70% tax share (tax/reward tokens
/// only). Pass address(0) to default to the creator. Ignored for fair launches.
/// @param metadataURI free-form metadata (description + socials JSON), emitted and stored
/// @dev Optional first buy: send ETH with the call and it is swapped to the new token
/// for the caller in the same transaction (pool is created here, so the buy
/// cannot be front-run or sandwiched).
function launch(
string calldata name,
string calldata symbol,
uint256 supply,
uint256 virtualEth,
uint24 fee,
uint8 tokenType,
uint16 buyTaxBps,
uint16 sellTaxBps,
uint16 devAllocBps,
address taxRecipient,
string calldata metadataURI
) external payable nonReentrant returns (address token, address pool, uint256 positionId) {
require(supply >= 1e18, "supply too small");
require(supply <= 1e18 * 1e15, "supply too large");
require(virtualEth >= MIN_VIRTUAL_ETH && virtualEth <= MAX_VIRTUAL_ETH, "virtualEth out of range");
require(tokenType <= 2, "bad token type");
require(devAllocBps <= MAX_DEV_ALLOC_BPS, "dev alloc too high");
if (tokenType == 0) require(buyTaxBps == 0 && sellTaxBps == 0, "fair launch cannot tax");
int24 tickSpacing = _tickSpacing(fee);
token = tokenDeployer.deployToken(tokenType, name, symbol, supply, address(this), msg.sender, buyTaxBps, sellTaxBps, taxRecipient, metadataURI);
bool tokenIs0 = token < weth;
(address token0, address token1) = tokenIs0 ? (token, weth) : (weth, token);
// Price as a Q64.192 ratio of token1 per token0, from the virtual ETH figure.
uint256 ratioX192 = tokenIs0
? FullMath.mulDiv(virtualEth, 1 << 192, supply) // WETH per token
: FullMath.mulDiv(supply, 1 << 192, virtualEth); // token per WETH
uint160 sqrtPriceX96 = uint160(_sqrt(ratioX192));
int24 rawTick = TickMath.getTickAtSqrtRatio(sqrtPriceX96);
int24 maxUsable = _maxUsableTick(tickSpacing);
// Align the launch tick so the position sits exactly at / beyond the current
// price and can be minted with tokens only (zero ETH).
int24 launchTick;
int24 tickLower;
int24 tickUpper;
if (tokenIs0) {
launchTick = _floorTick(rawTick, tickSpacing);
require(launchTick <= maxUsable - tickSpacing, "price too high");
require(launchTick >= -maxUsable, "price too low");
tickLower = launchTick;
tickUpper = maxUsable;
} else {
launchTick = _ceilTick(rawTick, tickSpacing);
require(launchTick >= -maxUsable + tickSpacing, "price too high");
require(launchTick <= maxUsable, "price too low");
tickLower = -maxUsable;
tickUpper = launchTick;
}
uint160 launchSqrtPrice = TickMath.getSqrtRatioAtTick(launchTick);
pool = positionManager.createAndInitializePoolIfNecessary(token0, token1, fee, launchSqrtPrice);
if (tokenType != 0) ITaxableToken(token).setPool(pool);
// Optional dev allocation: send the creator their slice up front; the rest is
// locked as LP. The starting price/tick is set from the FULL supply above, so the
// launch market cap is unchanged — the allocation only reduces pool depth.
uint256 lpAmount = supply;
if (devAllocBps > 0) {
uint256 devAmount = supply * devAllocBps / 10_000;
lpAmount = supply - devAmount;
require(lpAmount > 0, "nothing to lock");
require(IERC20Minimal(token).transfer(msg.sender, devAmount), "dev alloc transfer failed");
}
IERC20Minimal(token).approve(address(positionManager), lpAmount);
uint128 liquidity;
(positionId, liquidity,,) = positionManager.mint(
INonfungiblePositionManager.MintParams({
token0: token0,
token1: token1,
fee: fee,
tickLower: tickLower,
tickUpper: tickUpper,
amount0Desired: tokenIs0 ? lpAmount : 0,
amount1Desired: tokenIs0 ? 0 : lpAmount,
amount0Min: 0,
amount1Min: 0,
recipient: address(this),
deadline: block.timestamp
})
);
require(liquidity > 0, "no liquidity minted");
launches.push(
LaunchInfo({
token: token,
pool: pool,
creator: msg.sender,
positionId: positionId,
supply: supply,
virtualEth: virtualEth,
fee: fee,
launchedAt: uint40(block.timestamp),
tokenType: tokenType,
buyTaxBps: buyTaxBps,
sellTaxBps: sellTaxBps,
devAllocBps: devAllocBps,
metadataURI: metadataURI
})
);
launchIndexPlusOne[token] = launches.length;
emit TokenLaunched(token, msg.sender, pool, positionId, supply, virtualEth, fee, tokenType, buyTaxBps, sellTaxBps, devAllocBps, taxRecipient, name, symbol, metadataURI);
if (msg.value > 0) {
uint256 bought = swapRouter.exactInputSingle{value: msg.value}(
ISwapRouter02.ExactInputSingleParams({
tokenIn: weth,
tokenOut: token,
fee: fee,
recipient: msg.sender,
amountIn: msg.value,
amountOutMinimum: 0, // pool was created in this tx — nothing can front-run it
sqrtPriceLimitX96: 0
})
);
emit FirstBuy(token, msg.sender, msg.value, bought);
}
}
/// @notice Claim accrued swap fees for a launch. Only the creator may call.
/// Fees split 70/30: 70% to the creator's chosen recipient (WETH unwrapped
/// to ETH), 30% to the protocol fee recipient to fund app marketing &
/// maintenance. A protocol recipient that rejects ETH gets WETH instead —
/// it can never block a creator's claim.
function claimFees(address token, address recipient) external nonReentrant returns (uint256 creatorEth, uint256 creatorTokens) {
require(recipient != address(0), "zero recipient");
LaunchInfo storage info = _getLaunch(token);
require(msg.sender == info.creator, "not creator");
(uint256 amount0, uint256 amount1) = positionManager.collect(
INonfungiblePositionManager.CollectParams({
tokenId: info.positionId,
recipient: address(this),
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
bool tokenIs0 = token < weth;
uint256 wethAmount = tokenIs0 ? amount1 : amount0;
uint256 tokenAmount = tokenIs0 ? amount0 : amount1;
uint256 protocolEth = wethAmount * PROTOCOL_FEE_BPS / 10_000;
uint256 protocolTokens = tokenAmount * PROTOCOL_FEE_BPS / 10_000;
creatorEth = wethAmount - protocolEth;
creatorTokens = tokenAmount - protocolTokens;
if (wethAmount > 0) {
IWETH9(weth).withdraw(wethAmount);
(bool ok,) = recipient.call{value: creatorEth}("");
require(ok, "eth send failed");
if (protocolEth > 0) {
(bool okProtocol,) = protocolFeeRecipient.call{value: protocolEth}("");
if (!okProtocol) {
IWETH9(weth).deposit{value: protocolEth}();
require(IERC20Minimal(weth).transfer(protocolFeeRecipient, protocolEth), "weth send failed");
}
}
}
if (creatorTokens > 0) {
require(IERC20Minimal(token).transfer(recipient, creatorTokens), "token send failed");
}
if (protocolTokens > 0) {
require(IERC20Minimal(token).transfer(protocolFeeRecipient, protocolTokens), "token send failed");
}
emit FeesClaimed(token, msg.sender, recipient, creatorEth, creatorTokens, protocolEth, protocolTokens);
}
/// @notice Number of tokens launched through this contract.
function launchesCount() external view returns (uint256) {
return launches.length;
}
/// @notice Launch info for a token address (reverts for unknown tokens).
function getLaunch(address token) external view returns (LaunchInfo memory) {
return _getLaunch(token);
}
function _getLaunch(address token) private view returns (LaunchInfo storage) {
uint256 idxPlusOne = launchIndexPlusOne[token];
require(idxPlusOne != 0, "unknown token");
return launches[idxPlusOne - 1];
}
function _tickSpacing(uint24 fee) private pure returns (int24) {
if (fee == 10000) return 200;
if (fee == 3000) return 60;
if (fee == 500) return 10;
revert("unsupported fee tier");
}
function _maxUsableTick(int24 tickSpacing) private pure returns (int24) {
return (TickMath.MAX_TICK / tickSpacing) * tickSpacing;
}
function _floorTick(int24 tick, int24 tickSpacing) private pure returns (int24) {
int24 compressed = tick / tickSpacing;
if (tick < 0 && tick % tickSpacing != 0) compressed--;
return compressed * tickSpacing;
}
function _ceilTick(int24 tick, int24 tickSpacing) private pure returns (int24) {
int24 compressed = tick / tickSpacing;
if (tick > 0 && tick % tickSpacing != 0) compressed++;
return compressed * tickSpacing;
}
/// @dev Babylonian square root (floor).
function _sqrt(uint256 x) private pure returns (uint256 z) {
if (x == 0) return 0;
uint256 xx = x;
uint256 r = 1;
if (xx >= 0x100000000000000000000000000000000) {
xx >>= 128;
r <<= 64;
}
if (xx >= 0x10000000000000000) {
xx >>= 64;
r <<= 32;
}
if (xx >= 0x100000000) {
xx >>= 32;
r <<= 16;
}
if (xx >= 0x10000) {
xx >>= 16;
r <<= 8;
}
if (xx >= 0x100) {
xx >>= 8;
r <<= 4;
}
if (xx >= 0x10) {
xx >>= 4;
r <<= 2;
}
if (xx >= 0x4) {
r <<= 1;
}
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
uint256 r1 = x / r;
z = r < r1 ? r : r1;
}
/// @dev Required for IWETH9.withdraw
receive() external payable {
require(msg.sender == weth, "direct eth not accepted");
}
}
Chain explorer3573msChain node77ms