ArchrLauncher

0x54db23feb1652a1c5294af7859ef09465f83f387

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
8,256 bytes
ABI entries
32
13 read · 6 write
License
none

Contract information

Address
0x54db23feb1652a1c5294af7859ef09465f83f387
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0x07aafe352c…3594a0b311

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (13)

FEE()uint24
LP_BPS()uint256
MAX_USABLE_TICK()int24
MIN_USABLE_TICK()int24
NPM()address
SUPPLY()uint256
TICK_SPACING()int24
WETH()address
launched()bool
onERC721Received(address, address, uint256, bytes)bytes4
owner()address
pendingOwner()address
renounceOwnership()

Events (3)

LaunchedOwnershipTransferStartedOwnershipTransferred

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_npm",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "AlreadyLaunched",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "BadTick",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PoolPrecreated",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "RenounceDisabled",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ZeroDeployer",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "pool",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "lpTokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      }
    ],
    "name": "Launched",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferStarted",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "FEE",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "LP_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_USABLE_TICK",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MIN_USABLE_TICK",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "NPM",
    "outputs": [
      {
        "internalType": "contract INonfungiblePositionManager",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TICK_SPACING",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "WETH",
    "outputs": [
      {
        "internalType": "contract IWETH9",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "acceptOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      }
    ],
    "name": "collect",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "a0",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "a1",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      },
      {
        "internalType": "int24",
        "name": "launchTick",
        "type": "int24"
      },
      {
        "internalType": "address",
        "name": "deployer",
        "type": "address"
      }
    ],
    "name": "launch",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "pool",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "lpTokenId",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launched",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "name": "onERC721Received",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingOwner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      }
    ],
    "name": "sweepEth",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "t",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      }
    ],
    "name": "sweepToken",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20 as IERC20OZ} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {TickMath} from "./lib/TickMath.sol";
import {RedditToken} from "./RedditToken.sol";
import {IERC20} from "./interfaces/IERC20.sol";
import {IWETH9} from "./interfaces/IWETH9.sol";
import {INonfungiblePositionManager} from "./interfaces/INonfungiblePositionManager.sol";
import {IUniswapV3Pool} from "./interfaces/IUniswapV3Pool.sol";

contract ArchrLauncher is Ownable2Step, IERC721Receiver {
    using SafeERC20 for IERC20OZ;

    INonfungiblePositionManager public immutable NPM;
    IWETH9 public constant WETH = IWETH9(0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73);
    uint24 public constant FEE = 10000;
    int24 public constant TICK_SPACING = 200;
    int24 public constant MIN_USABLE_TICK = -887200;
    int24 public constant MAX_USABLE_TICK = 887200;
    uint256 public constant SUPPLY = 1_000_000_000e18;
    uint256 public constant LP_BPS = 7000;

    bool public launched;

    event Launched(address indexed token, address indexed pool, uint256 lpTokenId, address deployer);

    error BadTick();
    error AlreadyLaunched();
    error PoolPrecreated();
    error RenounceDisabled();
    error ZeroDeployer();

    constructor(address _npm) Ownable(msg.sender) {
        NPM = INonfungiblePositionManager(_npm);
    }

    function launch(bytes32 salt, int24 launchTick, address deployer)
        external
        onlyOwner
        returns (address token, address pool, uint256 lpTokenId)
    {
        if (launched) revert AlreadyLaunched();
        if (deployer == address(0)) revert ZeroDeployer();
        if (launchTick % TICK_SPACING != 0 || launchTick <= MIN_USABLE_TICK || launchTick >= MAX_USABLE_TICK) {
            revert BadTick();
        }
        launched = true;

        token = address(new RedditToken{salt: salt}("Archr", "ARCHR"));
        require(token > address(WETH), "token must sort above WETH");

        (pool, lpTokenId) = _initPoolAndMint(token, launchTick, deployer);
        emit Launched(token, pool, lpTokenId, deployer);
    }

    function _initPoolAndMint(address token, int24 launchTick, address deployer)
        internal
        returns (address pool, uint256 lpTokenId)
    {
        pool =
            NPM.createAndInitializePoolIfNecessary(address(WETH), token, FEE, TickMath.getSqrtRatioAtTick(launchTick));

        (, int24 curTick,,,,,) = IUniswapV3Pool(pool).slot0();
        if (curTick != launchTick) revert PoolPrecreated();

        uint256 lpAmount = (SUPPLY * LP_BPS) / 10000;
        IERC20(token).transfer(deployer, SUPPLY - lpAmount);

        IERC20(token).approve(address(NPM), lpAmount);
        (lpTokenId,,,) = NPM.mint(
            INonfungiblePositionManager.MintParams({
                token0: address(WETH),
                token1: token,
                fee: FEE,
                tickLower: MIN_USABLE_TICK,
                tickUpper: launchTick,
                amount0Desired: 0,
                amount1Desired: lpAmount,
                amount0Min: 0,
                amount1Min: 0,
                recipient: address(this),
                deadline: block.timestamp
            })
        );
    }

    function collect(uint256 id, address to) external onlyOwner returns (uint256 a0, uint256 a1) {
        (a0, a1) = NPM.collect(INonfungiblePositionManager.CollectParams(id, to, type(uint128).max, type(uint128).max));
    }

    function sweepToken(address t, address to) external onlyOwner {
        IERC20OZ(t).safeTransfer(to, IERC20OZ(t).balanceOf(address(this)));
    }

    function sweepEth(address to) external onlyOwner {
        (bool ok,) = to.call{value: address(this).balance}("");
        require(ok, "ETH transfer failed");
    }

    function renounceOwnership() public view override onlyOwner {
        revert RenounceDisabled();
    }

    function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {
        return IERC721Receiver.onERC721Received.selector;
    }

    receive() external payable {}
}
Chain explorer5092msChain node86ms