TokenFactory

0x31321e9fef6ff05c5c9c823306fc25f29a33eae8

Verification
Verified
v0.8.20+commit.a1b79de6
Type
Contract
8,897 bytes
ABI entries
27
14 read · 6 write
License
none

Contract information

Address
0x31321e9fef6ff05c5c9c823306fc25f29a33eae8
Chain
Robinhood Chain (4663)
Compiler
v0.8.20+commit.a1b79de6
Optimization
Enabled
Creation tx
0xed24e5a797…a20502a942

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (14)

CREATOR_ALLOCATION()uint256
LIQUIDITY_ALLOCATION()uint256
feeDistributor()address
launchCreator(uint256)address
launchIdByToken(address)uint256
launchPool(uint256)address
launchTimestamp(uint256)uint256
launchToken(uint256)address
launchTokenId(uint256)uint256
launcher()address
nextLaunchId()uint256
owner()address
predictTokenAddress(string, string, bytes32)address
totalLaunches()uint256

Events (5)

BnbWithdrawnOwnershipTransferredTokenCreatorRecipientUpdatedTokenLaunchedTokenWithdrawn

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "launcher_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "feeDistributor_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "BnbWithdrawn",
    "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"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "launchId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "previousRecipient",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "newRecipient",
        "type": "address"
      }
    ],
    "name": "TokenCreatorRecipientUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "launchId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "deploySalt",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "creatorAllocation",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "liquidityAllocation",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "pool",
        "type": "address"
      }
    ],
    "name": "TokenLaunched",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "TokenWithdrawn",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "CREATOR_ALLOCATION",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "LIQUIDITY_ALLOCATION",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      },
      {
        "internalType": "uint256",
        "name": "devBnbAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "minDevTokenAmount",
        "type": "uint256"
      }
    ],
    "name": "createAndLaunch",
    "outputs": [
      {
        "internalType": "address",
        "name": "tokenAddress",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "launchId",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "pool",
        "type": "address"
      }
    ],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "feeDistributor",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "launchCreator",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "launchIdByToken",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "launchPool",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "launchTimestamp",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "launchToken",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "launchTokenId",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launcher",
    "outputs": [
      {
        "internalType": "contract LiquidityLauncherV3",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "nextLaunchId",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      }
    ],
    "name": "predictTokenAddress",
    "outputs": [
      {
        "internalType": "address",
        "name": "tokenAddress",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "launchId",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "setLaunchCreatorRecipient",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "setTokenCreatorRecipient",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalLaunches",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address payable",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "withdrawAllBNB",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "withdrawAllToken",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import "./StandardToken.sol";
import "./LiquidityLauncherV3.sol";

interface IRescueToken {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
}

interface IFactorySwapRouter {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    function exactInputSingle(ExactInputSingleParams calldata params)
        external
        payable
        returns (uint256 amountOut);
}

interface IFeeRecipientManager {
    function setTokenCreatorRecipientByManager(address token, address creator, address recipient) external;
    function tokenCreatorRecipient(address token) external view returns (address);
}

contract TokenFactory {
    LiquidityLauncherV3 public immutable launcher;
    address public immutable feeDistributor;

    address internal constant WETH = 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73;
    address internal constant SWAP_ROUTER = 0xCaf681a66D020601342297493863E78C959E5cb2;
    uint24 internal constant FEE = 10000;

    uint256 public constant CREATOR_ALLOCATION = 0;
    uint256 public constant LIQUIDITY_ALLOCATION = 1_000_000_000 * 10 ** 18;

    address public owner;

    uint256 public nextLaunchId = 1;

    mapping(uint256 => address) public launchToken;
    mapping(uint256 => address) public launchCreator;
    mapping(uint256 => address) public launchPool;
    mapping(uint256 => uint256) public launchTokenId;
    mapping(uint256 => uint256) public launchTimestamp;
    mapping(address => uint256) public launchIdByToken;

    event TokenLaunched(
        uint256 indexed launchId,
        address indexed token,
        address indexed creator,
        bytes32 deploySalt,
        uint256 creatorAllocation,
        uint256 liquidityAllocation,
        uint256 tokenId,
        address pool
    );
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event BnbWithdrawn(address indexed recipient, uint256 amount);
    event TokenWithdrawn(address indexed token, address indexed recipient, uint256 amount);
    event TokenCreatorRecipientUpdated(
        uint256 indexed launchId,
        address indexed token,
        address indexed creator,
        address previousRecipient,
        address newRecipient
    );

    modifier onlyOwner() {
        require(msg.sender == owner, "ONLY_OWNER");
        _;
    }

    constructor(address launcher_, address feeDistributor_) {
        require(launcher_ != address(0), "ZERO_LAUNCHER");
        require(feeDistributor_ != address(0), "ZERO_DISTRIBUTOR");
        launcher = LiquidityLauncherV3(payable(launcher_));
        feeDistributor = feeDistributor_;
        owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }

    receive() external payable {}

    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "ZERO_OWNER");
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

    function withdrawAllBNB(address payable recipient) external onlyOwner returns (uint256 amount) {
        require(recipient != address(0), "ZERO_RECIPIENT");
        amount = address(this).balance;
        (bool ok, ) = recipient.call{value: amount}("");
        require(ok, "BNB_WITHDRAW_FAILED");
        emit BnbWithdrawn(recipient, amount);
    }

    function withdrawAllToken(address token, address recipient) external onlyOwner returns (uint256 amount) {
        require(token != address(0), "ZERO_TOKEN");
        require(recipient != address(0), "ZERO_RECIPIENT");
        amount = IRescueToken(token).balanceOf(address(this));
        (bool ok, bytes memory data) = token.call(
            abi.encodeWithSelector(IRescueToken.transfer.selector, recipient, amount)
        );
        require(ok && (data.length == 0 || abi.decode(data, (bool))), "TOKEN_WITHDRAW_FAILED");
        emit TokenWithdrawn(token, recipient, amount);
    }

    function setTokenCreatorRecipient(address token, address recipient) external onlyOwner {
        require(token != address(0), "ZERO_TOKEN");
        uint256 launchId = launchIdByToken[token];
        require(launchId != 0, "UNKNOWN_TOKEN");
        _setLaunchCreatorRecipient(launchId, recipient);
    }

    function setLaunchCreatorRecipient(uint256 launchId, address recipient) external onlyOwner {
        _setLaunchCreatorRecipient(launchId, recipient);
    }

    function createAndLaunch(
        string calldata name,
        string calldata symbol,
        bytes32 salt,
        uint256 devBnbAmount,
        uint256 minDevTokenAmount
    ) external payable returns (address tokenAddress, uint256 tokenId, uint256 launchId, address pool) {
        require(salt != bytes32(0), "SALT_REQUIRED");
        require(msg.value >= devBnbAmount, "INSUFFICIENT_BNB");

        uint256 previousBalance = address(this).balance - msg.value;
        uint256 launchBnbAmount = msg.value - devBnbAmount;

        launchId = nextLaunchId++;
        tokenAddress = _deployToken(name, symbol, salt);

        StandardToken newToken = StandardToken(payable(tokenAddress));
        require(newToken.balanceOf(address(this)) == CREATOR_ALLOCATION + LIQUIDITY_ALLOCATION, "BAD_SUPPLY");

        newToken.approve(address(launcher), LIQUIDITY_ALLOCATION);
        (tokenId, pool) = launcher.launchAndLock{value: launchBnbAmount}(
            tokenAddress,
            LIQUIDITY_ALLOCATION,
            msg.sender
        );

        if (devBnbAmount > 0) {
            uint256 beforeDevBalance = newToken.balanceOf(msg.sender);
            _devBuy(tokenAddress, devBnbAmount);
            uint256 receivedDevTokens = newToken.balanceOf(msg.sender) - beforeDevBalance;
            require(receivedDevTokens >= minDevTokenAmount, "DEV_BUY_SLIPPAGE");
        }

        uint256 dust = newToken.balanceOf(address(this));
        if (dust > 0) newToken.transfer(msg.sender, dust);

        uint256 refundable = address(this).balance - previousBalance;
        if (refundable > 0) {
            (bool ok, ) = payable(msg.sender).call{value: refundable}("");
            require(ok, "REFUND_FAILED");
        }

        launchToken[launchId] = tokenAddress;
        launchCreator[launchId] = msg.sender;
        launchPool[launchId] = pool;
        launchTokenId[launchId] = tokenId;
        launchTimestamp[launchId] = block.timestamp;
        launchIdByToken[tokenAddress] = launchId;

        emit TokenLaunched(
            launchId,
            tokenAddress,
            msg.sender,
            salt,
            CREATOR_ALLOCATION,
            LIQUIDITY_ALLOCATION,
            tokenId,
            pool
        );
    }

    function _deployToken(
        string calldata name,
        string calldata symbol,
        bytes32 salt
    ) internal returns (address tokenAddress) {
        bytes memory bytecode = abi.encodePacked(
            type(StandardToken).creationCode,
            abi.encode(name, symbol)
        );

        tokenAddress = address(
            uint160(uint256(keccak256(abi.encodePacked(hex"ff", address(this), salt, keccak256(bytecode)))))
        );

        StandardToken newToken = new StandardToken{salt: salt}(
            name,
            symbol
        );
        require(address(newToken) == tokenAddress, "CREATE2_MISMATCH");
    }

    function _devBuy(address tokenAddress, uint256 devBnbAmount)
        internal
        returns (uint256)
    {
        IFactorySwapRouter.ExactInputSingleParams memory params = IFactorySwapRouter.ExactInputSingleParams({
            tokenIn: WETH,
            tokenOut: tokenAddress,
            fee: FEE,
            recipient: msg.sender,
            amountIn: devBnbAmount,
            amountOutMinimum: 0,
            sqrtPriceLimitX96: 0
        });

        return IFactorySwapRouter(SWAP_ROUTER).exactInputSingle{value: devBnbAmount}(params);
    }

    function predictTokenAddress(
        string calldata name,
        string calldata symbol,
        bytes32 salt
    ) external view returns (address tokenAddress) {
        bytes memory bytecode = abi.encodePacked(
            type(StandardToken).creationCode,
            abi.encode(name, symbol)
        );

        tokenAddress = address(
            uint160(uint256(keccak256(abi.encodePacked(hex"ff", address(this), salt, keccak256(bytecode)))))
        );
    }

    function totalLaunches() external view returns (uint256) {
        return nextLaunchId - 1;
    }

    function _setLaunchCreatorRecipient(uint256 launchId, address recipient) internal {
        require(launchId > 0 && launchId < nextLaunchId, "UNKNOWN_LAUNCH");
        require(recipient != address(0), "ZERO_RECIPIENT");

        address token = launchToken[launchId];
        address creator = launchCreator[launchId];
        require(token != address(0), "TOKEN_NOT_SET");
        require(creator != address(0), "CREATOR_NOT_SET");

        address previousRecipient = IFeeRecipientManager(feeDistributor).tokenCreatorRecipient(token);
        IFeeRecipientManager(feeDistributor).setTokenCreatorRecipientByManager(token, creator, recipient);
        emit TokenCreatorRecipientUpdated(launchId, token, creator, previousRecipient, recipient);
    }
}
Chain explorer1860msChain node89ms