LaunchToken

0x8a2d7dbf1a243b22f874243c42d7cace5e072f5e

Verification
Verified
v0.8.30+commit.73712a01
Type
Contract
4,830 bytes
ABI entries
41
26 read · 3 write
License
none

Contract information

Address
0x8a2d7dbf1a243b22f874243c42d7cace5e072f5e
Chain
Robinhood Chain (4663)
Compiler
v0.8.30+commit.73712a01
Optimization
Enabled
Creation tx
0xe070da17a2…3d94a173e3

Token

Name
Aristotle Hood
Symbol
ARIS
Decimals
18
Holders
5

Read contract (26)

allowance(address, address)uint256
balanceOf(address)uint256
decimals()uint8
deployer()address
description()string
dexFactory()address
getTokenInfo()tuple
launchBlock()uint256
launchFactory()address
liquidityPool()address
logo()string
maxTxAmount()uint256
maxTxBps()uint16
maxTxLimit()uint256
maxWalletAmount()uint256
maxWalletBps()uint16
maxWalletLimit()uint256
name()string
pairToken()address
poolFee()uint24
positionManager()address
restrictionBlocks()uint32
restrictionEndBlock()uint256
socials()tuple
symbol()string
totalSupply()uint256

Events (2)

ApprovalTransfer

ABI

[
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "name",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "symbol",
            "type": "string"
          },
          {
            "internalType": "uint256",
            "name": "supply",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "pairToken",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "positionManager",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "dexFactory",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "poolFee",
            "type": "uint24"
          },
          {
            "internalType": "uint16",
            "name": "maxWalletBps",
            "type": "uint16"
          },
          {
            "internalType": "uint16",
            "name": "maxTxBps",
            "type": "uint16"
          },
          {
            "internalType": "uint32",
            "name": "restrictionBlocks",
            "type": "uint32"
          }
        ],
        "internalType": "struct LauncherTypes.TokenConfig",
        "name": "config",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "deployer",
            "type": "address"
          },
          {
            "internalType": "string",
            "name": "logo",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "components": [
              {
                "internalType": "string",
                "name": "telegram",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "twitter",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "discord",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "website",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "farcaster",
                "type": "string"
              }
            ],
            "internalType": "struct LauncherTypes.Socials",
            "name": "socials",
            "type": "tuple"
          }
        ],
        "internalType": "struct LauncherTypes.TokenInfo",
        "name": "info",
        "type": "tuple"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "allowance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "approver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidApprover",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidReceiver",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSender",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSpender",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "LaunchBlockBuyBlocked",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxTx",
        "type": "uint256"
      }
    ],
    "name": "MaxTxExceeded",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balanceAfter",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxWallet",
        "type": "uint256"
      }
    ],
    "name": "MaxWalletExceeded",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "deployer",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "description",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "dexFactory",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getTokenInfo",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "deployer",
            "type": "address"
          },
          {
            "internalType": "string",
            "name": "logo",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "description",
            "type": "string"
          },
          {
            "components": [
              {
                "internalType": "string",
                "name": "telegram",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "twitter",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "discord",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "website",
                "type": "string"
              },
              {
                "internalType": "string",
                "name": "farcaster",
                "type": "string"
              }
            ],
            "internalType": "struct LauncherTypes.Socials",
            "name": "socials",
            "type": "tuple"
          }
        ],
        "internalType": "struct LauncherTypes.TokenInfo",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchBlock",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchFactory",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "liquidityPool",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "logo",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxTxAmount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxTxBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxTxLimit",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxWalletAmount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxWalletBps",
    "outputs": [
      {
        "internalType": "uint16",
        "name": "",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxWalletLimit",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pairToken",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "poolFee",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "positionManager",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "restrictionBlocks",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "restrictionEndBlock",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "socials",
    "outputs": [
      {
        "components": [
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "discord",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "farcaster",
            "type": "string"
          }
        ],
        "internalType": "struct LauncherTypes.Socials",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT

// throbbin.xyz
// x.com/throbbinxyz
// the bird with a boner

pragma solidity ^0.8.30;

// OpenZeppelin ERC-20 implementation.
// Verification requires @openzeppelin/contracts v5.2.0.
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/// @notice Minimal interface used to resolve the Uniswap V3 liquidity pool.
interface IUniswapV3Factory {
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
}

/// @notice Shared constructor and metadata types used by the launcher.
library LauncherTypes {
    /// @notice Public-facing social links associated with the token.
    struct Socials {
        string telegram;
        string twitter;
        string discord;
        string website;
        string farcaster;
    }

    /// @notice Immutable trading and launch configuration.
    struct TokenConfig {
        string name;
        string symbol;
        uint256 supply;
        address pairToken;
        address positionManager;
        address dexFactory;
        uint24 poolFee;
        uint16 maxWalletBps;
        uint16 maxTxBps;
        uint32 restrictionBlocks;
    }

    /// @notice Token metadata supplied by the launcher.
    struct TokenInfo {
        address deployer;
        string logo;
        string description;
        Socials socials;
    }
}

/// @title LaunchToken
/// @notice ERC-20 token with launch-block anti-buy protection and temporary
///         max-transaction / max-wallet restrictions.
/// @dev Comments do not affect the reproduced bytecode because verification
///      uses metadata.bytecodeHash = "none".
contract LaunchToken is ERC20 {
    error MaxWalletExceeded(address account, uint256 balanceAfter, uint256 maxWallet);
    error MaxTxExceeded(address account, uint256 amount, uint256 maxTx);
    error LaunchBlockBuyBlocked(address account);

    // Human-readable token metadata.
    LauncherTypes.TokenInfo private _tokenInfo;

    // Tracks cumulative pool purchases by transaction origin while restrictions
    // are active. This is intentionally keyed by tx.origin in the deployed code.
    mapping(address account => uint256 amount) private _originBought;

    // Launcher and DEX configuration fixed at deployment.
    address public immutable launchFactory;
    address public immutable pairToken;
    address public immutable positionManager;
    address public immutable dexFactory;
    uint24 public immutable poolFee;

    // Temporary launch restriction parameters.
    uint16 public immutable maxWalletBps;
    uint16 public immutable maxTxBps;
    uint32 public immutable restrictionBlocks;
    uint256 public immutable launchBlock;
    uint256 public immutable restrictionEndBlock;
    uint256 public immutable maxWalletAmount;
    uint256 public immutable maxTxAmount;

    constructor(LauncherTypes.TokenConfig memory config, LauncherTypes.TokenInfo memory info)
        ERC20(config.name, config.symbol)
    {
        // Record the launcher and immutable DEX configuration.
        launchFactory = msg.sender;
        pairToken = config.pairToken;
        positionManager = config.positionManager;
        dexFactory = config.dexFactory;
        poolFee = config.poolFee;

        // Convert basis-point limits into absolute token amounts.
        maxWalletBps = config.maxWalletBps;
        maxTxBps = config.maxTxBps;
        restrictionBlocks = config.restrictionBlocks;
        launchBlock = block.number;
        restrictionEndBlock =
            config.restrictionBlocks == 0 ? block.number : block.number + config.restrictionBlocks;
        maxWalletAmount = (config.supply * config.maxWalletBps) / 10_000;
        maxTxAmount = (config.supply * config.maxTxBps) / 10_000;

        // Persist display metadata and mint the full supply to the launcher.
        _tokenInfo = info;
        _mint(msg.sender, config.supply);
    }

    /// @notice Resolves the configured Uniswap V3 pool.
    function liquidityPool() public view returns (address) {
        return IUniswapV3Factory(dexFactory).getPool(address(this), pairToken, poolFee);
    }

    /// @notice Returns the absolute maximum wallet balance during restrictions.
    function maxWalletLimit() external view returns (uint256) {
        return maxWalletAmount;
    }

    /// @notice Returns the absolute maximum cumulative buy amount during restrictions.
    function maxTxLimit() external view returns (uint256) {
        return maxTxAmount;
    }

    /// @notice Returns all stored token metadata.
    function getTokenInfo() external view returns (LauncherTypes.TokenInfo memory) {
        return _tokenInfo;
    }

    /// @notice Returns the original token deployer recorded by the launcher.
    function deployer() external view returns (address) {
        return _tokenInfo.deployer;
    }

    /// @notice Returns the token logo URI.
    function logo() external view returns (string memory) {
        return _tokenInfo.logo;
    }

    /// @notice Returns the token description.
    function description() external view returns (string memory) {
        return _tokenInfo.description;
    }

    /// @notice Returns the configured social links.
    function socials() external view returns (LauncherTypes.Socials memory) {
        return _tokenInfo.socials;
    }

    /// @dev Applies launch-block protection and temporary trading restrictions
    ///      before delegating the balance update to OpenZeppelin ERC20.
    function _update(address from, address to, uint256 value) internal override {
        bool restrictionsActive = block.number > launchBlock && block.number <= restrictionEndBlock;
        address pool;
        bool onLaunchBlock = block.number == launchBlock;

        // Pool-dependent restrictions are disabled until the pool exists.
        if (restrictionsActive || onLaunchBlock) {
            pool = liquidityPool();
            if (pool == address(0)) {
                restrictionsActive = false;
                onLaunchBlock = false;
            }
        }

        // Block pool buys during the exact deployment block, except for the
        // launcher factory and the recorded deployer.
        if (
            onLaunchBlock &&
            value > 0 &&
            from == pool &&
            to != launchFactory &&
            to != _tokenInfo.deployer
        ) {
            revert LaunchBlockBuyBlocked(to);
        }

        if (restrictionsActive && value > 0) {
            // Limit cumulative pool buys by tx.origin with a 10% buffer over
            // the configured maximum transaction amount.
            if (from == pool && to != launchFactory && to != _tokenInfo.deployer) {
                uint256 bought = _originBought[tx.origin] + value;
                _originBought[tx.origin] = bought;
                uint256 maxBuy = (maxTxAmount * 11_000) / 10_000;
                if (maxBuy == 0 || bought > maxBuy) {
                    revert MaxTxExceeded(tx.origin, bought, maxBuy);
                }
            }

            // Enforce the maximum wallet amount for ordinary recipients.
            // Minting, the launcher, deployer, and pool are exempt.
            if (
                from != address(0) &&
                to != launchFactory &&
                to != _tokenInfo.deployer &&
                to != pool
            ) {
                uint256 balanceAfter = balanceOf(to) + value;
                if (balanceAfter > maxWalletAmount) {
                    revert MaxWalletExceeded(to, balanceAfter, maxWalletAmount);
                }
            }
        }

        super._update(from, to, value);
    }
}
Chain explorer8225msChain node75ms