PonsLauncherToken

0xedaee44320107caa714baaec486261a87f27022d

Verification
Verified
v0.8.30+commit.73712a01
Type
Contract
5,274 bytes
ABI entries
44
26 read · 4 write
License
none

Contract information

Address
0xedaee44320107caa714baaec486261a87f27022d
Chain
Robinhood Chain (4663)
Compiler
v0.8.30+commit.73712a01
Optimization
Enabled
Creation tx
0x4c58b8a764…4cdc6f6116

Token

Name
PONGO
Symbol
PONGO
Decimals
18
Holders
1,394

Read contract (26)

allowance(address, address)uint256
balanceOf(address)uint256
decimals()uint8
deployer()address
description()string
dexFactory()address
getTokenInfo()address, string, string, 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()uint256
restrictionEndBlock()uint256
socials()string, string, string, string, string
symbol()string
totalSupply()uint256

Events (2)

ApprovalTransfer

ABI

[
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "logo_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "description_",
        "type": "string"
      },
      {
        "components": [
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "discord",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "farcaster",
            "type": "string"
          }
        ],
        "internalType": "struct PonsLauncherToken.Socials",
        "name": "socials_",
        "type": "tuple"
      },
      {
        "internalType": "address",
        "name": "deployer_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "dexFactory_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "positionManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "pairToken_",
        "type": "address"
      },
      {
        "internalType": "uint24",
        "name": "poolFee_",
        "type": "uint24"
      },
      {
        "internalType": "uint256",
        "name": "supply_",
        "type": "uint256"
      },
      {
        "internalType": "uint16",
        "name": "maxWalletBps_",
        "type": "uint16"
      },
      {
        "internalType": "uint16",
        "name": "maxTxBps_",
        "type": "uint16"
      },
      {
        "internalType": "uint32",
        "name": "restrictionBlocks_",
        "type": "uint32"
      }
    ],
    "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": "recipient",
        "type": "address"
      }
    ],
    "name": "LaunchBlockBuyBlocked",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "attempted",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "limit",
        "type": "uint256"
      }
    ],
    "name": "MaxTxExceeded",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "limit",
        "type": "uint256"
      }
    ],
    "name": "MaxWalletExceeded",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotLaunchFactory",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ZeroAddress",
    "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": [
      {
        "internalType": "address",
        "name": "tokenDeployer",
        "type": "address"
      },
      {
        "internalType": "string",
        "name": "tokenLogo",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "tokenDescription",
        "type": "string"
      },
      {
        "components": [
          {
            "internalType": "string",
            "name": "twitter",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "telegram",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "discord",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "website",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "farcaster",
            "type": "string"
          }
        ],
        "internalType": "struct PonsLauncherToken.Socials",
        "name": "tokenSocials",
        "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": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "restrictionEndBlock",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "setInitialBuyRecipient",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "socials",
    "outputs": [
      {
        "internalType": "string",
        "name": "twitter",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "telegram",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "discord",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "website",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "farcaster",
        "type": "string"
      }
    ],
    "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
pragma solidity ^0.8.30;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IUniswapV3FactoryLike, IUniswapV3PoolImmutablesLike} from "./interfaces/ILaunchpad.sol";

/**
 * @title PonsLauncherToken
 * @notice Fixed-supply ERC-20 deployed by PonsLaunchFactory for a V3 launch.
 * Launch protections only apply to buys from the canonical pool during the
 * configured restriction window. Afterward the token behaves as a plain ERC-20.
 */
contract PonsLauncherToken is ERC20 {
    struct Socials {
        string twitter;
        string telegram;
        string discord;
        string website;
        string farcaster;
    }

    error LaunchBlockBuyBlocked(address recipient);
    error MaxWalletExceeded(address account, uint256 balance, uint256 limit);
    error MaxTxExceeded(address recipient, uint256 attempted, uint256 limit);
    error NotLaunchFactory();
    error ZeroAddress();

    address public immutable deployer;
    address public immutable launchFactory;
    address public immutable dexFactory;
    address public immutable positionManager;
    address public immutable pairToken;
    uint24 public immutable poolFee;

    uint256 public immutable launchBlock;
    uint256 public immutable restrictionBlocks;
    uint256 public immutable restrictionEndBlock;
    uint16 public immutable maxWalletBps;
    uint16 public immutable maxTxBps;

    string public logo;
    string public description;

    Socials private _socials;
    address private _initialBuyRecipient;
    mapping(address recipient => uint256 amount) private _restrictedPoolBuys;

    /**
     * @notice Creates a launch token and mints its entire supply to the factory.
     */
    constructor(
        string memory name_,
        string memory symbol_,
        string memory logo_,
        string memory description_,
        Socials memory socials_,
        address deployer_,
        address dexFactory_,
        address positionManager_,
        address pairToken_,
        uint24 poolFee_,
        uint256 supply_,
        uint16 maxWalletBps_,
        uint16 maxTxBps_,
        uint32 restrictionBlocks_
    ) ERC20(name_, symbol_) {
        if (
            deployer_ == address(0) || dexFactory_ == address(0) || positionManager_ == address(0)
                || pairToken_ == address(0)
        ) {
            revert ZeroAddress();
        }

        deployer = deployer_;
        launchFactory = msg.sender;
        dexFactory = dexFactory_;
        positionManager = positionManager_;
        pairToken = pairToken_;
        poolFee = poolFee_;
        launchBlock = block.number;
        restrictionBlocks = restrictionBlocks_;
        restrictionEndBlock = block.number + restrictionBlocks_;
        maxWalletBps = maxWalletBps_;
        maxTxBps = maxTxBps_;
        logo = logo_;
        description = description_;
        _socials = socials_;

        _mint(msg.sender, supply_);
    }

    /**
     * @notice Returns the canonical V3 pool once the factory has created it.
     */
    function liquidityPool() public view returns (address) {
        return IUniswapV3FactoryLike(dexFactory).getPool(address(this), pairToken, poolFee);
    }

    /**
     * @notice Returns the launch token's five social metadata fields.
     */
    function socials()
        external
        view
        returns (
            string memory twitter,
            string memory telegram,
            string memory discord,
            string memory website,
            string memory farcaster
        )
    {
        Socials memory values = _socials;
        return (values.twitter, values.telegram, values.discord, values.website, values.farcaster);
    }

    /**
     * @notice Returns creator and metadata in the launcher-compatible tuple.
     */
    function getTokenInfo()
        external
        view
        returns (
            address tokenDeployer,
            string memory tokenLogo,
            string memory tokenDescription,
            Socials memory tokenSocials
        )
    {
        return (deployer, logo, description, _socials);
    }

    /**
     * @notice Maximum recipient balance during the restricted launch window.
     */
    function maxWalletLimit() public view returns (uint256) {
        return (totalSupply() * maxWalletBps) / 10_000;
    }

    /**
     * @notice Compatibility alias for maxWalletLimit.
     */
    function maxWalletAmount() external view returns (uint256) {
        return maxWalletLimit();
    }

    /**
     * @notice Base cumulative pool-buy limit during the restricted window.
     */
    function maxTxLimit() public view returns (uint256) {
        return (totalSupply() * maxTxBps) / 10_000;
    }

    /**
     * @notice Compatibility alias for maxTxLimit.
     */
    function maxTxAmount() external view returns (uint256) {
        return maxTxLimit();
    }

    /**
     * @notice Opens or closes the one-call exemption used by the factory's atomic initial buy.
     */
    function setInitialBuyRecipient(address recipient) external {
        if (msg.sender != launchFactory) revert NotLaunchFactory();
        _initialBuyRecipient = recipient;
    }

    /**
     * @dev Applies the observed launch restrictions only to pool-to-user buys.
     * The factory opens a narrow recipient exemption only while its atomic
     * initial buy is executing.
     */
    function _update(address from, address to, uint256 value) internal override {
        if (from != address(0) && to != address(0) && block.number <= restrictionEndBlock) {
            bool isRestrictedBuy = _isPairPool(from);
            if (!isRestrictedBuy) {
                super._update(from, to, value);
                return;
            }

            bool isAtomicLaunchBuy =
                block.number == launchBlock && _initialBuyRecipient != address(0) && to == _initialBuyRecipient;
            if (!isAtomicLaunchBuy && block.number == launchBlock) {
                revert LaunchBlockBuyBlocked(to);
            }

            if (!isAtomicLaunchBuy) {
                uint256 walletLimit = maxWalletLimit();
                uint256 resultingBalance = balanceOf(to) + value;
                if (resultingBalance > walletLimit) {
                    revert MaxWalletExceeded(to, resultingBalance, walletLimit);
                }

                uint256 cumulative = _restrictedPoolBuys[to] + value;
                uint256 cumulativeLimit = maxTxLimit();
                if (cumulative > cumulativeLimit) {
                    revert MaxTxExceeded(to, cumulative, cumulativeLimit);
                }
                _restrictedPoolBuys[to] = cumulative;
            }
        }

        super._update(from, to, value);
    }

    /**
     * @notice Identifies any V3 pool registered by the configured factory for
     * this token and its paired asset, regardless of fee tier.
     */
    function _isPairPool(address candidate) private view returns (bool) {
        address canonicalPool = liquidityPool();
        if (candidate == canonicalPool && canonicalPool != address(0)) return true;
        if (candidate.code.length == 0) return false;

        (bool feeRead, bytes memory feeData) =
            candidate.staticcall(abi.encodeCall(IUniswapV3PoolImmutablesLike.fee, ()));
        if (!feeRead || feeData.length < 32) return false;

        uint24 candidateFee = abi.decode(feeData, (uint24));
        return IUniswapV3FactoryLike(dexFactory).getPool(address(this), pairToken, candidateFee) == candidate;
    }
}
Chain explorer5457msChain node86ms