HoloLaunch

0x5c8884546837066e3f3b573d3cb8b5c9efbd7c77

Verification
Verified
v0.8.23+commit.f704f362
Type
Contract
20,572 bytes
ABI entries
44
21 read · 9 write
License
none

Contract information

Address
0x5c8884546837066e3f3b573d3cb8b5c9efbd7c77
Chain
Robinhood Chain (4663)
Compiler
v0.8.23+commit.f704f362
Optimization
Enabled
Creation tx
0xd6e11065a5…be13188b7d

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (21)

creatorTokenIds(address, uint256)uint256
feeCollector()address
getBaseTokenCostForTokens(uint256, uint256)uint256
getDeployedAddress(string, string, uint256, address, uint256)address
getFeeCollector()address
getLaunchFee()uint256
getMaxInitialPurchaseTokens(uint256)uint256
getParameters(uint256)tuple
getPositionManager()address
getTokenData(uint256)tuple
getTokenIdsByCreator(address)uint256[]
getTokensForBaseToken(uint256, uint256)uint256
launchFee()uint256
liquidityManagerContractAddr()address
owner()address
parameters(uint256)uint256, uint256, uint256, uint256
pendingOwner()address
positionManager()address
renounceOwnership()
tokenIdCounter()uint256
tokenRecords(uint256)address, address, uint256, uint256, uint256, uint256

Events (7)

ConstructorOwnershipTransferStartedOwnershipTransferredSetFeeCollectorSetParametersSetPositionManagerTokenDeployed

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_feeCollector",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_positionManager",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_liquidityManagerContractAddr",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "_launchFee",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "Create2EmptyBytecode",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "Create2FailedDeployment",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "Create2InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "feeCollector",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "positionManager",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "liquidityManagerContractAddress",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "launchFee",
        "type": "uint256"
      }
    ],
    "name": "Constructor",
    "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"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "feeCollector",
        "type": "address"
      }
    ],
    "name": "SetFeeCollector",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "index",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "vBaseToken",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "vToken",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "targetBaseToken",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "initialSupply",
        "type": "uint256"
      }
    ],
    "name": "SetParameters",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "positionManager",
        "type": "address"
      }
    ],
    "name": "SetPositionManager",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "tokenAddr",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "creator",
        "type": "address"
      }
    ],
    "name": "TokenDeployed",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "acceptOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "creatorTokenIds",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "parametersIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "initialPurchaseAmount",
        "type": "uint256"
      }
    ],
    "name": "deployToken",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "feeCollector",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "parametersIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      }
    ],
    "name": "getBaseTokenCostForTokens",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "parametersIndex",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "initialPurchaseBaseToken",
        "type": "uint256"
      }
    ],
    "name": "getDeployedAddress",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getFeeCollector",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getLaunchFee",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "parametersIndex",
        "type": "uint256"
      }
    ],
    "name": "getMaxInitialPurchaseTokens",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "index",
        "type": "uint256"
      }
    ],
    "name": "getParameters",
    "outputs": [
      {
        "components": [
          {
            "internalType": "uint256",
            "name": "vBaseToken",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "vToken",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "targetBaseToken",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "initialSupply",
            "type": "uint256"
          }
        ],
        "internalType": "struct HoloLaunch.Parameters",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getPositionManager",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "getTokenData",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "tokenAddress",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "creator",
            "type": "address"
          },
          {
            "internalType": "uint256",
            "name": "vBaseToken",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "vToken",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "targetBaseToken",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "initialSupply",
            "type": "uint256"
          }
        ],
        "internalType": "struct HoloLaunch.TokenData",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      }
    ],
    "name": "getTokenIdsByCreator",
    "outputs": [
      {
        "internalType": "uint256[]",
        "name": "",
        "type": "uint256[]"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "parametersIndex",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "baseTokenAmount",
        "type": "uint256"
      }
    ],
    "name": "getTokensForBaseToken",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchFee",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "liquidityManagerContractAddr",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "parameters",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "vBaseToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "vToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "targetBaseToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "initialSupply",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "pauseToken",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingOwner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "positionManager",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "resumeToken",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_feeCollector",
        "type": "address"
      }
    ],
    "name": "setFeeCollector",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "index",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "vBaseToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "vToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "targetBaseToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "initialSupply",
        "type": "uint256"
      }
    ],
    "name": "setParameters",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_positionManager",
        "type": "address"
      }
    ],
    "name": "setPositionManager",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tokenIdCounter",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "tokenRecords",
    "outputs": [
      {
        "internalType": "address",
        "name": "tokenAddress",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "creator",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "vBaseToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "vToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "targetBaseToken",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "initialSupply",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "transferLiquidityToDex",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "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.23;

import "./BondingCurveERC20.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/utils/Create2.sol";

/// @author web3roy
/// @title HoloLaunch
/// @dev Launchpad contract for deploying ERC20 tokens with bonding curves.
///      Provides a platform for creators to deploy new tokens and manage their bonding curves.
///      Facilitates the transfer of liquidity to decentralized exchanges.
contract HoloLaunch is Ownable2Step {
    event Constructor(
        address feeCollector,
        address positionManager,
        address liquidityManagerContractAddress,
        uint256 launchFee
    );
    event TokenDeployed(
        address indexed tokenAddr,
        uint256 indexed tokenId,
        address indexed creator
    );
    event SetPositionManager(address positionManager);
    event SetFeeCollector(address feeCollector);
    event SetParameters(
        uint256 index,
        uint256 vBaseToken,
        uint256 vToken,
        uint256 targetBaseToken,
        uint256 initialSupply
    );

    struct TokenData {
        address tokenAddress;
        address creator;
        uint256 vBaseToken;
        uint256 vToken;
        uint256 targetBaseToken;
        uint256 initialSupply;
    }

    struct Parameters {
        uint256 vBaseToken;
        uint256 vToken;
        uint256 targetBaseToken;
        uint256 initialSupply;
    }

    mapping(uint256 => Parameters) public parameters;
    mapping(uint256 => TokenData) public tokenRecords;
    mapping(address => uint256[]) public creatorTokenIds;
    address public immutable liquidityManagerContractAddr;
    uint256 public immutable launchFee;
    uint256 public tokenIdCounter;
    address public feeCollector;
    address public positionManager;

    /// @dev Minimum-value floor enforced by the four `require`s in `setParameters`.
    ///      One whole token / 1 ETH at 18 decimals. Guards against a parameter set
    ///      whose values are so small the curve's integer math degenerates.
    uint256 private constant MIN_PARAM_VALUE = 10 ** 18;

    /// @notice Constructor to initialize the Launchpad contract with fee collector and position manager addresses
    constructor(
        address _feeCollector,
        address _positionManager,
        address _liquidityManagerContractAddr,
        uint256 _launchFee
    ) Ownable(msg.sender) {
        require(_feeCollector != address(0), "Invalid fee collector");
        require(_positionManager != address(0), "Invalid position manager");
        feeCollector = _feeCollector;
        positionManager = _positionManager;
        liquidityManagerContractAddr = _liquidityManagerContractAddr;
        launchFee = _launchFee;
        emit Constructor(
            feeCollector,
            positionManager,
            liquidityManagerContractAddr,
            launchFee
        );
    }

    receive() external payable {}

    /// @notice Allows the owner to set a new fee collector address
    /// @param _feeCollector The address of the new fee collector
    function setFeeCollector(address _feeCollector) external onlyOwner {
        require(_feeCollector != address(0), "Invalid fee collector");
        feeCollector = _feeCollector;
        emit SetFeeCollector(_feeCollector);
    }

    /// @notice Allows the owner to set a new position manager address
    /// @param _positionManager The address of the new position manager
    function setPositionManager(address _positionManager) external onlyOwner {
        require(_positionManager != address(0), "Invalid position manager");
        positionManager = _positionManager;
        emit SetPositionManager(_positionManager);
    }

    /// @notice Sets the bonding curve parameters for a specific index
    /// @param index The index of the parameter set
    /// @param vBaseToken Virtual BaseToken value
    /// @param vToken Virtual Token value
    /// @param targetBaseToken Target BaseToken value for liquidity transfer
    /// @param initialSupply Initial supply of the token
    function setParameters(
        uint256 index,
        uint256 vBaseToken,
        uint256 vToken,
        uint256 targetBaseToken,
        uint256 initialSupply
    ) external onlyOwner {
        require(parameters[index].vBaseToken == 0, "Parameters already set");
        require(vBaseToken > MIN_PARAM_VALUE, "vBaseToken below minimum");
        require(vToken > MIN_PARAM_VALUE, "vToken below minimum");
        require(targetBaseToken > MIN_PARAM_VALUE, "targetBaseToken below minimum");
        require(initialSupply > MIN_PARAM_VALUE, "initialSupply below minimum");
        uint256 k = vBaseToken * (vToken + initialSupply);
        uint256 expectEndTokenReserve = k / (vBaseToken + targetBaseToken);
        uint256 tokenDownsizingRatio = (10 ** 5 *
            (expectEndTokenReserve - vToken)) / expectEndTokenReserve;
        uint256 baseTokenDownsizingRatio = (10 ** 5 * targetBaseToken) /
            (vBaseToken + targetBaseToken);
        if (tokenDownsizingRatio > baseTokenDownsizingRatio) {
            require(
                (baseTokenDownsizingRatio * 101) / 100 > tokenDownsizingRatio,
                "Price difference exceeds 1%"
            );
        } else {
            require(
                (tokenDownsizingRatio * 101) / 100 > baseTokenDownsizingRatio,
                "Price difference exceeds 1%"
            );
        }
        parameters[index] = Parameters(
            vBaseToken,
            vToken,
            targetBaseToken,
            initialSupply
        );
        emit SetParameters(
            index,
            vBaseToken,
            vToken,
            targetBaseToken,
            initialSupply
        );
    }

    /// @notice Deploys a new token contract based on the provided parameters
    /// @param name The name of the new token
    /// @param symbol The symbol of the new token
    /// @param parametersIndex The index of the parameter set to use
    /// @param initialPurchaseAmount The amount of initial purchase BaseToken
    /// @return The address of the newly deployed token contract
    function deployToken(
        string memory name,
        string memory symbol,
        uint256 parametersIndex,
        uint256 initialPurchaseAmount
    ) external payable returns (address) {
        address expectedTokenAddress = getDeployedAddress(
            name,
            symbol,
            parametersIndex,
            msg.sender,
            initialPurchaseAmount
        );
        if (initialPurchaseAmount > 0) {
            require(
                msg.value == initialPurchaseAmount + launchFee,
                "Incorrect BaseToken amount sent"
            );
            require(
                msg.value > launchFee,
                "Insufficient BaseToken amount to pay the launch fee"
            );
            (bool feeTransferSuccess, ) = feeCollector.call{value: launchFee}(
                ""
            );
            require(feeTransferSuccess, "Fee transfer failed");
            (bool success, ) = expectedTokenAddress.call{
                value: initialPurchaseAmount
            }("");
            require(success, "Transfer to new token contract failed");
        }

        Parameters memory params = parameters[parametersIndex];
        require(
            params.vBaseToken != 0 &&
                params.vToken != 0 &&
                params.targetBaseToken != 0 &&
                params.initialSupply != 0,
            "Invalid parameters"
        );

        bytes memory bytecode = type(BondingCurveERC20).creationCode;
        bytes memory bytecodeWithArgs = abi.encodePacked(
            bytecode,
            abi.encode(
                name,
                symbol,
                parametersIndex,
                address(this),
                msg.sender,
                initialPurchaseAmount
            )
        );

        bytes32 salt = keccak256(
            abi.encodePacked(
                name,
                symbol,
                parametersIndex,
                msg.sender,
                tokenIdCounter
            )
        );

        address addr = Create2.deploy(0, salt, bytecodeWithArgs);

        require(addr == expectedTokenAddress, "Invalid token address");

        tokenRecords[tokenIdCounter] = TokenData(
            addr,
            msg.sender,
            params.vBaseToken,
            params.vToken,
            params.targetBaseToken,
            params.initialSupply
        );

        // Add tokenId to the creator's array
        creatorTokenIds[msg.sender].push(tokenIdCounter);

        tokenIdCounter++;
        emit TokenDeployed(addr, tokenIdCounter - 1, msg.sender);
        return addr;
    }

    /// @notice Pauses the bonding curve for a specific token
    /// @param tokenId The ID of the token to pause
    function pauseToken(uint256 tokenId) external onlyOwner {
        BondingCurveERC20 token = BondingCurveERC20(
            payable(tokenRecords[tokenId].tokenAddress)
        );
        token.pauseBondingCurve();
    }

    /// @notice Resumes the bonding curve for a specific token
    /// @param tokenId The ID of the token to resume
    function resumeToken(uint256 tokenId) external onlyOwner {
        BondingCurveERC20 token = BondingCurveERC20(
            payable(tokenRecords[tokenId].tokenAddress)
        );
        token.resumeBondingCurve();
    }

    /// @notice Transfers liquidity to a decentralized exchange
    /// @param tokenId The ID of the token for which liquidity is being transferred
    function transferLiquidityToDex(
        uint256 tokenId
    ) external onlyOwner returns (address) {
        BondingCurveERC20 token = BondingCurveERC20(
            payable(tokenRecords[tokenId].tokenAddress)
        );
        address poolAddr = token.transferLiquidityToDEX(
            liquidityManagerContractAddr
        );
        return poolAddr;
    }

    /// @notice Calculates the deployed address of a token contract
    /// @param name The name of the new token
    /// @param symbol The symbol of the new token
    /// @param parametersIndex The index of the parameter set to use
    /// @param creator The address of the creator
    /// @param initialPurchaseBaseToken The amount of initial purchase BaseToken
    /// @return The expected address of the deployed token contract
    function getDeployedAddress(
        string memory name,
        string memory symbol,
        uint256 parametersIndex,
        address creator,
        uint256 initialPurchaseBaseToken
    ) public view returns (address) {
        Parameters memory params = parameters[parametersIndex];
        require(
            params.vBaseToken != 0 &&
                params.vToken != 0 &&
                params.targetBaseToken != 0 &&
                params.initialSupply != 0,
            "Invalid parameters"
        );

        bytes memory bytecode = type(BondingCurveERC20).creationCode;
        bytes memory bytecodeWithArgs = abi.encodePacked(
            bytecode,
            abi.encode(
                name,
                symbol,
                parametersIndex,
                address(this),
                creator,
                initialPurchaseBaseToken
            )
        );

        bytes32 salt = keccak256(
            abi.encodePacked(
                name,
                symbol,
                parametersIndex,
                creator,
                tokenIdCounter
            )
        );
        return
            Create2.computeAddress(
                salt,
                keccak256(bytecodeWithArgs),
                address(this)
            );
    }

    /// @notice Returns the current fee collector address
    /// @return The address of the fee collector
    function getFeeCollector() public view returns (address) {
        return feeCollector;
    }

    /// @notice Returns the current position manager address
    /// @return The address of the position manager
    function getPositionManager() public view returns (address) {
        return positionManager;
    }

    /// @notice Returns the current launch fee
    /// @return The amount of the launch fee
    function getLaunchFee() public view returns (uint256) {
        return launchFee;
    }

    /// @notice Returns the bonding curve parameters for a specific index
    /// @param index The index of the parameter set
    /// @return The Parameters struct containing the parameters
    function getParameters(
        uint256 index
    ) public view returns (Parameters memory) {
        return parameters[index];
    }

    /// @notice Returns the list of token IDs created by a specific creator
    /// @param creator The address of the creator
    /// @return An array of token IDs
    function getTokenIdsByCreator(
        address creator
    ) public view returns (uint256[] memory) {
        return creatorTokenIds[creator];
    }

    /// @notice Retrieves data for a specific token
    /// @param tokenId The ID of the token
    /// @return TokenData struct containing the token's information
    function getTokenData(
        uint256 tokenId
    ) public view returns (TokenData memory) {
        return tokenRecords[tokenId];
    }

    /// @notice Prevent accidental renouncement of ownership
    function renounceOwnership() public view override onlyOwner {
        revert("Cannot renounce ownership");
    }

    /// @notice Returns the maximum number of tokens that can be purchased during the initial purchase.
    /// @param parametersIndex The index of the parameters set to use.
    /// @return The maximum number of tokens that can be purchased.
    function getMaxInitialPurchaseTokens(
        uint256 parametersIndex
    ) public view returns (uint256) {
        Parameters memory params = parameters[parametersIndex];
        // The maximum number of tokens that can be purchased is 3% of the initial supply
        uint256 maxTokens = (params.initialSupply * 3) / 100;
        return maxTokens;
    }

    /// @notice Calculates the cost in baseToken for a given amount of tokens during the initial buy.
    /// @param parametersIndex The index of the parameters set to use.
    /// @param tokenAmount The amount of tokens to purchase.
    /// @return The cost in baseToken.
    function getBaseTokenCostForTokens(
        uint256 parametersIndex,
        uint256 tokenAmount
    ) public view returns (uint256) {
        Parameters memory params = parameters[parametersIndex];
        uint256 maxTokens = (params.initialSupply * 3) / 100;
        require(
            tokenAmount <= maxTokens,
            "Token amount exceeds the maximum purchase limit"
        );
        uint256 k = params.vBaseToken * (params.vToken + params.initialSupply);
        uint256 newY = params.vToken + params.initialSupply - tokenAmount;
        uint256 newX = k / newY;
        uint256 baseTokenCostWithoutFee = newX - params.vBaseToken;
        uint256 baseTokenCost = (baseTokenCostWithoutFee * 100) / 99; // Including 1% fee
        return baseTokenCost + launchFee;
    }

    /// @notice Calculates the amount of tokens that can be purchased with a given amount of baseToken during the initial buy.
    /// @param parametersIndex The index of the parameters set to use.
    /// @param baseTokenAmount The amount of baseToken to use for purchasing tokens.
    /// @return The amount of tokens that can be purchased.
    function getTokensForBaseToken(
        uint256 parametersIndex,
        uint256 baseTokenAmount
    ) public view returns (uint256) {
        Parameters memory params = parameters[parametersIndex];
        uint256 netBaseTokenAmount = baseTokenAmount - launchFee;
        uint256 k = params.vBaseToken * (params.vToken + params.initialSupply);
        uint256 fee = (netBaseTokenAmount * 1) / 100;
        uint256 netAmountIn = netBaseTokenAmount - fee;
        uint256 newX = params.vBaseToken + netAmountIn;
        uint256 newY = k / newX;
        uint256 tokenAmount = params.vToken + params.initialSupply - newY;
        return tokenAmount;
    }
}
Chain explorer3900msChain node98ms