LaunchTokenDeployer

0xde044a3c4321476d9826a98bbc6c50126e29f628

Verification
Verified
v0.8.24+commit.e11b9ed9
Type
Contract
6,296 bytes
ABI entries
10
3 read · 1 write
License
mit

Contract information

Address
0xde044a3c4321476d9826a98bbc6c50126e29f628
Chain
Robinhood Chain (4663)
Compiler
v0.8.24+commit.e11b9ed9
Optimization
Enabled
Creation tx
0xc0a8a2ef4f…4a72a97b4a

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (3)

CREATE3_PROXY_BYTECODE_HASH()bytes32
launchpad()address
predictTokenAddress(bytes32)address

Events (1)

TokenDeployed

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "launchpad_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "InvalidAddress",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "OnlyLaunchpad",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ProxyDeploymentFailed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TokenDeploymentFailed",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      }
    ],
    "name": "TokenDeployed",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "CREATE3_PROXY_BYTECODE_HASH",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      },
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      }
    ],
    "name": "deployToken",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchpad",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "salt",
        "type": "bytes32"
      }
    ],
    "name": "predictTokenAddress",
    "outputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import {LaunchToken} from "./LaunchToken.sol";

// ************************************************
//  _  _   __    __  ____  ____  ____     _  _  ____  _  _  ____ 
// / )( \ /  \  /  \(    \(  __)(    \   ( \/ )(  __)( \/ )(  __)
// ) __ ((  O )(  O )) D ( ) _)  ) D ( _ / \/ \ ) _) / \/ \ ) _) 
// \_)(_/ \__/  \__/(____/(____)(____/(_)\_)(_/(____)\_)(_/(____)
//
// Website: https://hooded.meme
// Author: SwapHood Team (kellkell)
//
// ************************************************

/// @notice Deploys launch tokens to salt-derived addresses with the CREATE3 pattern.
/// @dev The final address depends only on this contract and `salt`, not on token constructor arguments.
contract LaunchTokenDeployer {
    error OnlyLaunchpad();
    error InvalidAddress();
    error ProxyDeploymentFailed();
    error TokenDeploymentFailed();

    // Creation code for a minimal proxy whose runtime copies calldata into memory and
    // CREATEs it. The token is therefore always the proxy's nonce-one CREATE address.
    bytes internal constant CREATE3_PROXY_BYTECODE = hex"67363d3d37363d34f03d5260086018f3";
    bytes32 public constant CREATE3_PROXY_BYTECODE_HASH = keccak256(CREATE3_PROXY_BYTECODE);

    address public immutable launchpad;

    event TokenDeployed(address indexed token, bytes32 indexed salt);

    constructor(address launchpad_) {
        if (launchpad_ == address(0)) revert InvalidAddress();
        launchpad = launchpad_;
    }

    function deployToken(bytes32 salt, string calldata name, string calldata symbol)
        external
        returns (address token)
    {
        if (msg.sender != launchpad) revert OnlyLaunchpad();

        bytes memory proxyBytecode = CREATE3_PROXY_BYTECODE;
        address proxy;
        assembly ("memory-safe") {
            proxy := create2(0, add(proxyBytecode, 0x20), mload(proxyBytecode), salt)
        }
        // A used salt leaves the proxy deployed, making CREATE2 return address(0).
        if (proxy == address(0)) revert ProxyDeploymentFailed();

        token = predictTokenAddress(salt);
        bytes memory creationCode =
            abi.encodePacked(type(LaunchToken).creationCode, abi.encode(name, symbol, launchpad));
        (bool success,) = proxy.call(creationCode);
        if (!success || token.code.length == 0) revert TokenDeploymentFailed();

        emit TokenDeployed(token, salt);
    }

    function predictTokenAddress(bytes32 salt) public view returns (address token) {
        address proxy = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(bytes1(0xff), address(this), salt, CREATE3_PROXY_BYTECODE_HASH)
                    )
                )
            )
        );
        token = address(
            uint160(uint256(keccak256(abi.encodePacked(hex"d694", proxy, hex"01"))))
        );
    }
}
Chain explorer4530msChain node76ms