LemonCurveFactory

0xbd65151cd894245ef980e136380efcf34ea2fec0

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
21,646 bytes
ABI entries
19
11 read · 4 write
License
none

Contract information

Address
0xbd65151cd894245ef980e136380efcf34ea2fec0
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xc3fd402367…776777e135

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (11)

ANTI_SNIPE_MAX_WALLET()uint256
ANTI_SNIPE_WINDOW_SECS()uint256
POOL_FEE()uint24
TOKEN_SUPPLY()uint256
admin()address
curveDeployer()address
getTokenInfo(address)tuple
keeper()address
launches(address)address, address, address, uint256, uint16, uint8, address, address, uint16
platformFeeReceiver()address
weth()address

Events (3)

CurveLaunchedKeeperSetTokenizedLaunched

ABI

[
  {
    "inputs": [
      {
        "internalType": "contract IWETH",
        "name": "_weth",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_platformFeeReceiver",
        "type": "address"
      },
      {
        "internalType": "contract CurveDeployer",
        "name": "_curveDeployer",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "curve",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "dexFactory",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "positionManager",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint8",
        "name": "dexKind",
        "type": "uint8"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "graduationThreshold",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "creatorFeeBps",
        "type": "uint16"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "tokenURI",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "timestamp",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "virtualTokenReserve",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "virtualEthReserve",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "totalSupply",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "initialTokenReserve",
        "type": "uint256"
      }
    ],
    "name": "CurveLaunched",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "keeper",
        "type": "address"
      }
    ],
    "name": "KeeperSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "curve",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "vault",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "stockToken",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "string",
        "name": "stockSymbol",
        "type": "string"
      },
      {
        "indexed": false,
        "internalType": "uint16",
        "name": "vaultBps",
        "type": "uint16"
      }
    ],
    "name": "TokenizedLaunched",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "ANTI_SNIPE_MAX_WALLET",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ANTI_SNIPE_WINDOW_SECS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "POOL_FEE",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TOKEN_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "admin",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "curveDeployer",
    "outputs": [
      {
        "internalType": "contract CurveDeployer",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "getTokenInfo",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "token",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "curve",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "deployer",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "graduationThreshold",
            "type": "uint256"
          },
          {
            "internalType": "uint16",
            "name": "creatorFeeBps",
            "type": "uint16"
          },
          {
            "internalType": "uint8",
            "name": "dexKind",
            "type": "uint8"
          },
          {
            "internalType": "bool",
            "name": "graduated",
            "type": "bool"
          },
          {
            "internalType": "address",
            "name": "poolAfterGraduation",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "lpLocker",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "tokenReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "ethReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualTokenReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualEthReserve",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "stocksVault",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "stockToken",
            "type": "address"
          },
          {
            "internalType": "uint16",
            "name": "vaultBps",
            "type": "uint16"
          }
        ],
        "internalType": "struct LemonCurveFactory.TokenInfo",
        "name": "info",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "keeper",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "tokenURI",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "dexFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "positionManager",
            "type": "address"
          },
          {
            "internalType": "uint8",
            "name": "dexKind",
            "type": "uint8"
          },
          {
            "internalType": "uint256",
            "name": "graduationThreshold",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualTokenReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualEthReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint16",
            "name": "creatorFeeBps",
            "type": "uint16"
          },
          {
            "internalType": "address",
            "name": "creatorFeeReceiver",
            "type": "address"
          },
          {
            "internalType": "string",
            "name": "logoURI",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          }
        ],
        "internalType": "struct LemonCurveFactory.LaunchParams",
        "name": "p",
        "type": "tuple"
      }
    ],
    "name": "launch",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "curve",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "tokenURI",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "dexFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "positionManager",
            "type": "address"
          },
          {
            "internalType": "uint8",
            "name": "dexKind",
            "type": "uint8"
          },
          {
            "internalType": "uint256",
            "name": "graduationThreshold",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualTokenReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "virtualEthReserve",
            "type": "uint256"
          },
          {
            "internalType": "uint16",
            "name": "creatorFeeBps",
            "type": "uint16"
          },
          {
            "internalType": "address",
            "name": "creatorFeeReceiver",
            "type": "address"
          },
          {
            "internalType": "string",
            "name": "logoURI",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          }
        ],
        "internalType": "struct LemonCurveFactory.LaunchParams",
        "name": "p",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "stockToken",
            "type": "address"
          },
          {
            "internalType": "string",
            "name": "stockSymbol",
            "type": "string"
          },
          {
            "internalType": "uint16",
            "name": "vaultBps",
            "type": "uint16"
          }
        ],
        "internalType": "struct LemonCurveFactory.TokenizedParams",
        "name": "t",
        "type": "tuple"
      }
    ],
    "name": "launchTokenized",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "curve",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "vault",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "launches",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "curve",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "graduationThreshold",
        "type": "uint256"
      },
      {
        "internalType": "uint16",
        "name": "creatorFeeBps",
        "type": "uint16"
      },
      {
        "internalType": "uint8",
        "name": "dexKind",
        "type": "uint8"
      },
      {
        "internalType": "address",
        "name": "stocksVault",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "stockToken",
        "type": "address"
      },
      {
        "internalType": "uint16",
        "name": "vaultBps",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "platformFeeReceiver",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_admin",
        "type": "address"
      }
    ],
    "name": "setAdmin",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_keeper",
        "type": "address"
      }
    ],
    "name": "setKeeper",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "weth",
    "outputs": [
      {
        "internalType": "contract IWETH",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {LemonToken} from "./LemonToken.sol";
import {BondingCurve} from "./BondingCurve.sol";
import {StocksVault} from "./StocksVault.sol";
import {IUniswapV3Factory, IUniswapV3Pool, INonfungiblePositionManager, IWETH} from "./interfaces/IUniswap.sol";
import {CurveDeployer} from "./deployers/CurveDeployer.sol";

/// @notice Factory that deploys LemonToken + BondingCurve pairs, with optional
/// StocksVault for tokenized launches that pay dividends in Robinhood Stock Tokens.
///
/// LemonToken is deployed directly by this factory so explorers/scanners see
/// the same one-hop internal contract-creation trace as the reference launchpad.
/// The large BondingCurve bytecode remains behind CurveDeployer to keep the
/// factory under EIP-170 without hiding the token deployment from indexers.
contract LemonCurveFactory {
    uint256 public constant TOKEN_SUPPLY = 1_000_000_000e18;
    uint24  public constant POOL_FEE = 10_000;
    uint256 public constant ANTI_SNIPE_MAX_WALLET = 10_000_000e18; // 1% of supply, scanner parity
    uint256 public constant ANTI_SNIPE_WINDOW_SECS = 900;

    IWETH public immutable weth;
    address public immutable platformFeeReceiver;
    CurveDeployer public immutable curveDeployer;
    address public keeper; // one keeper wallet powers every vault

    address public admin; // can rotate keeper

    struct Launched {
        address token;
        address curve;
        address deployer;
        uint256 graduationThreshold;
        uint16  creatorFeeBps;
        uint8   dexKind;    // 0 = Uniswap, 1 = Sushi
        address stocksVault; // 0 for regular launches
        address stockToken;  // 0 for regular launches
        uint16  vaultBps;    // 0 for regular launches
    }

    mapping(address token => Launched) public launches;

    event CurveLaunched(
        address indexed token,
        address indexed curve,
        address indexed deployer,
        address dexFactory,
        address positionManager,
        uint8   dexKind,
        uint256 graduationThreshold,
        uint16  creatorFeeBps,
        string  name,
        string  symbol,
        string  tokenURI,
        uint256 timestamp,
        uint256 virtualTokenReserve,
        uint256 virtualEthReserve,
        uint256 totalSupply,
        uint256 initialTokenReserve
    );

    /// @notice Fired only for tokenized launches so indexers can render the
    /// "Pays $AAPL dividends" badge without decoding constructor args.
    event TokenizedLaunched(
        address indexed token,
        address indexed curve,
        address indexed vault,
        address stockToken,
        string  stockSymbol,
        uint16  vaultBps
    );

    event KeeperSet(address indexed keeper);

    constructor(
        IWETH _weth,
        address _platformFeeReceiver,
        CurveDeployer _curveDeployer
    ) {
        weth = _weth;
        platformFeeReceiver = _platformFeeReceiver;
        curveDeployer = _curveDeployer;
        admin = msg.sender;
    }

    function setKeeper(address _keeper) external {
        require(msg.sender == admin, "admin");
        require(_keeper != address(0), "zero");
        keeper = _keeper;
        emit KeeperSet(_keeper);
    }

    function setAdmin(address _admin) external {
        require(msg.sender == admin, "admin");
        require(_admin != address(0), "zero");
        admin = _admin;
    }

    struct LaunchParams {
        string  name;
        string  symbol;
        string  tokenURI;
        address dexFactory;
        address positionManager;
        uint8   dexKind;
        uint256 graduationThreshold;
        uint256 virtualTokenReserve;
        uint256 virtualEthReserve;
        uint16  creatorFeeBps;
        address creatorFeeReceiver;
        // On-chain metadata
        string  logoURI;
        string  description;
        string  twitter;
        string  telegram;
        string  website;
    }

    struct TokenizedParams {
        address stockToken;
        string  stockSymbol;
        uint16  vaultBps;
    }

    function launch(LaunchParams calldata p) external returns (address token, address curve) {
        (token, curve, ) = _launchInternal(p, TokenizedParams({stockToken: address(0), stockSymbol: "", vaultBps: 0}), false);
    }

    function launchTokenized(LaunchParams calldata p, TokenizedParams calldata t)
        external
        returns (address token, address curve, address vault)
    {
        require(t.stockToken != address(0), "stock=0");
        require(t.vaultBps > 0 && t.vaultBps <= 500, "vaultBps");
        require(bytes(t.stockSymbol).length > 0 && bytes(t.stockSymbol).length <= 12, "sym");
        (token, curve, vault) = _launchInternal(p, t, true);
        emit TokenizedLaunched(token, curve, vault, t.stockToken, t.stockSymbol, t.vaultBps);
    }

    function _launchInternal(LaunchParams calldata p, TokenizedParams memory t, bool isTokenized)
        internal
        returns (address token, address curve, address vault)
    {
        require(bytes(p.name).length > 0 && bytes(p.symbol).length > 0, "meta");
        require(p.dexFactory != address(0) && p.positionManager != address(0), "dex");
        require(p.graduationThreshold > 0, "threshold=0");
        require(p.virtualEthReserve > 0 && p.virtualTokenReserve > 0, "vreserves");
        require(p.creatorFeeBps <= 1000, "creatorFee>10%");
        require(p.dexKind <= 1, "dexKind");

        token = address(new LemonToken(
            p.name,
            p.symbol,
            TOKEN_SUPPLY,
            address(this),
            p.logoURI,
            p.description,
            p.twitter,
            p.telegram,
            p.website
        ));

        if (isTokenized) {
            StocksVault v = new StocksVault(token, t.stockToken, admin);
            vault = address(v);
            if (keeper != address(0)) v.setKeeper(keeper);
        }

        curve = curveDeployer.deployCurve(CurveDeployer.Args({
            token: LemonToken(token),
            weth: weth,
            dexFactory: p.dexFactory,
            positionManager: p.positionManager,
            deployer: msg.sender,
            creatorFeeReceiver: p.creatorFeeReceiver == address(0) ? msg.sender : p.creatorFeeReceiver,
            platformFeeReceiver: platformFeeReceiver,
            creatorFeeBps: p.creatorFeeBps,
            graduationThreshold: p.graduationThreshold,
            virtualTokenReserve: p.virtualTokenReserve,
            virtualEthReserve: p.virtualEthReserve,
            stocksVault: vault,
            vaultBps: isTokenized ? t.vaultBps : uint16(0)
        }));

        _finalizeLaunch(token, curve);

        launches[token] = Launched({
            token: token,
            curve: curve,
            deployer: msg.sender,
            graduationThreshold: p.graduationThreshold,
            creatorFeeBps: p.creatorFeeBps,
            dexKind: p.dexKind,
            stocksVault: vault,
            stockToken: isTokenized ? t.stockToken : address(0),
            vaultBps: isTokenized ? t.vaultBps : uint16(0)
        });

        _emitCurveLaunched(token, curve, p);
    }

    /// @dev Seeds the curve with the full supply and locks in the launch
    /// protections. Pool wiring happens later, inside BondingCurve._graduate().
    function _finalizeLaunch(address token, address curve) internal {
        LemonToken tok = LemonToken(token);
        require(tok.transfer(curve, tok.totalSupply()), "seed");
        tok.configureLaunch(ANTI_SNIPE_MAX_WALLET, 0, ANTI_SNIPE_WINDOW_SECS);
        tok.initPoolSetter(curve);
    }

    function _emitCurveLaunched(address token, address curve, LaunchParams calldata p) internal {
        uint256 supply = LemonToken(token).totalSupply();
        emit CurveLaunched(
            token, curve, msg.sender,
            p.dexFactory, p.positionManager, p.dexKind,
            p.graduationThreshold, p.creatorFeeBps,
            p.name, p.symbol, p.tokenURI,
            block.timestamp,
            p.virtualTokenReserve, p.virtualEthReserve,
            supply, supply
        );
    }

    // --- Views ---

    struct TokenInfo {
        address token;
        address curve;
        address deployer;
        uint256 graduationThreshold;
        uint16  creatorFeeBps;
        uint8   dexKind;
        bool    graduated;
        address poolAfterGraduation;
        address lpLocker;
        uint256 tokenReserve;
        uint256 ethReserve;
        uint256 virtualTokenReserve;
        uint256 virtualEthReserve;
        address stocksVault;
        address stockToken;
        uint16  vaultBps;
    }

    function getTokenInfo(address token) external view returns (TokenInfo memory info) {
        Launched memory L = launches[token];
        info.token = L.token;
        info.curve = L.curve;
        info.deployer = L.deployer;
        info.graduationThreshold = L.graduationThreshold;
        info.creatorFeeBps = L.creatorFeeBps;
        info.dexKind = L.dexKind;
        info.stocksVault = L.stocksVault;
        info.stockToken = L.stockToken;
        info.vaultBps = L.vaultBps;
        if (L.curve == address(0)) return info;
        BondingCurve c = BondingCurve(payable(L.curve));
        info.graduated = c.graduated();
        info.poolAfterGraduation = c.poolAfterGraduation();
        info.lpLocker = c.lpLockerAddress();
        info.tokenReserve = c.tokenReserve();
        info.ethReserve = c.ethReserve();
        info.virtualTokenReserve = c.virtualTokenReserve();
        info.virtualEthReserve = c.virtualEthReserve();
    }

    function _ensurePoolConfigured(
        address token,
        address wethAddr,
        address factory,
        uint256 virtualTokenReserve,
        uint256 virtualEthReserve
    ) internal returns (address pool) {
        bool tokenIsToken0 = token < wethAddr;
        (address token0, address token1) = tokenIsToken0 ? (token, wethAddr) : (wethAddr, token);
        pool = IUniswapV3Factory(factory).getPool(token0, token1, POOL_FEE);
        if (pool == address(0)) {
            pool = IUniswapV3Factory(factory).createPool(token0, token1, POOL_FEE);
        }

        uint256 reserve0 = tokenIsToken0 ? TOKEN_SUPPLY + virtualTokenReserve : virtualEthReserve;
        uint256 reserve1 = tokenIsToken0 ? virtualEthReserve : TOKEN_SUPPLY + virtualTokenReserve;
        uint160 sqrtPriceX96 = _sqrtPriceX96(reserve1, reserve0);
        try IUniswapV3Pool(pool).initialize(sqrtPriceX96) {} catch {}
    }

    function _sqrtPriceX96(uint256 reserve1, uint256 reserve0) internal pure returns (uint160) {
        require(reserve0 > 0, "r0=0");
        uint256 ratioX96 = (reserve1 << 96) / reserve0;
        uint256 sqrtRatioX48 = _sqrt(ratioX96);
        uint256 result = sqrtRatioX48 << 48;
        require(result <= type(uint160).max, "sqrtPrice ovf");
        return uint160(result);
    }

    function _sqrt(uint256 x) internal pure returns (uint256) {
        if (x == 0) return 0;
        uint256 z = (x + 1) / 2;
        uint256 y = x;
        while (z < y) { y = z; z = (x / z + z) / 2; }
        return y;
    }
}
Chain explorer3270msChain node102ms