BondingCurve

Description:

Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "laxwin contracts/BondingCurve.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "./ILaxcePadInterfaces.sol";
import "./BondingCurveMath.sol";

contract BondingCurve is
    Initializable,
    ReentrancyGuardUpgradeable,
    UUPSUpgradeable,
    AccessControlUpgradeable,
    PausableUpgradeable,
    IBondingCurve
{
    using SafeERC20 for IERC20;
    using BondingCurveMath for BondingCurveMath.CurveConfig;

    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
    bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
    bytes32 public constant FACTORY_ROLE = keccak256("FACTORY_ROLE");

    uint256 public constant BASIS_POINTS = 10000;
    uint256 public constant PRECISION = 1e18;
    uint256 public constant MIN_PURCHASE = 0.001 ether;
    uint256 public constant MAX_SLIPPAGE = 1000;

    mapping(address => CurveParams) public curveParams;

    mapping(address => BondingCurveMath.CurveConfig) public curveConfigs;

    mapping(address => TokenStats) public tokenStats;

    mapping(address => mapping(address => UserTokenStats)) public userStats;

    struct GlobalSettings {
        uint256 tradingFeeRate;
        uint256 protocolFeeRate;
        address feeRecipient;
        address graduationManager;
        uint256 minLiquidity;
        uint256 maxPriceImpact;
    }

    GlobalSettings public globalSettings;

    struct TokenStats {
        uint256 totalBuys;
        uint256 totalSells;
        uint256 totalVolume;
        uint256 totalFees;
        uint256 uniqueTraders;
        uint256 lastTradeTime;
        uint256 allTimeHigh;
        uint256 allTimeLow;
    }

    struct UserTokenStats {
        uint256 totalBought;
        uint256 totalSold;
        uint256 totalSpent;
        uint256 totalReceived;
        uint256 firstBuyTime;
        uint256 lastTradeTime;
        bool hasTraded;
    }

    struct SellCalculation {
        uint256 currentSupply;
        uint256 ethOut;
        uint256 priceImpact;
        uint256 tradingFee;
        uint256 protocolFee;
        uint256 totalFee;
        uint256 netETH;
        uint256 newPrice;
    }

    address[] public activeTokens;
    mapping(address => bool) public isTokenActive;
    mapping(address => uint256) public tokenIndex;

    mapping(address => uint256) public userDailyVolume;
    mapping(address => uint256) public userLastReset;
    mapping(address => bool) public userBlacklist;
    
    mapping(address => uint256) public tokenGraduationDeadline;
    mapping(address => bool) public tokenFailed;
    
    mapping(address => mapping(address => uint256)) public userContributions;
    mapping(address => bool) public refundApproved;

    event CurveInitialized(
        address indexed token,
        uint256 supply,
        uint256 startPrice,
        uint256 targetMarketCap,
        BondingCurveMath.CurveType curveType
    );

    event TokenTraded(
        address indexed token,
        address indexed trader,
        bool isBuy,
        uint256 tokenAmount,
        uint256 ethAmount,
        uint256 newPrice,
        uint256 priceImpact,
        uint256 fee
    );

    event GlobalSettingsUpdated(GlobalSettings settings);

    event TokenGraduationReady(address indexed token, uint256 marketCap);
    event TokenFailed(address indexed token, uint256 deadline, uint256 raisedAmount);
    event RefundApproved(address indexed token, uint256 timestamp);
    event RefundClaimed(address indexed token, address indexed user, uint256 amount, uint256 adminFee);

    error BondingCurve__TokenNotInitialized();
    error BondingCurve__TokenAlreadyGraduated();
    error BondingCurve__InsufficientETH();
    error BondingCurve__InsufficientTokens();
    error BondingCurve__SlippageExceeded();
    error BondingCurve__PriceImpactTooHigh();
    error BondingCurve__UserBlacklisted();
    error BondingCurve__DailyLimitExceeded();
    error BondingCurve__InvalidParameters();
    error BondingCurve__NotAuthorized();
    error BondingCurve__TokenFailed();
    error BondingCurve__DeadlineNotReached();
    error BondingCurve__NoContribution();
    error BondingCurve__RefundNotApproved();

    modifier onlyActiveToken(address token) {
        if (!isTokenActive[token]) revert BondingCurve__TokenNotInitialized();
        if (curveParams[token].isGraduated) revert BondingCurve__TokenAlreadyGraduated();
        _;
    }

    modifier notBlacklisted() {
        if (userBlacklist[msg.sender]) revert BondingCurve__UserBlacklisted();
        _;
    }

    modifier checkDailyLimit(uint256 ethAmount) {
        _checkDailyLimit(msg.sender, ethAmount);
        _;
    }

    function initialize(
        address _admin,
        GlobalSettings memory _settings
    ) external initializer {
        __ReentrancyGuard_init();
        __UUPSUpgradeable_init();
        __AccessControl_init();
        __Pausable_init();

        _grantRole(DEFAULT_ADMIN_ROLE, _admin);
        _grantRole(ADMIN_ROLE, _admin);
        _grantRole(OPERATOR_ROLE, _admin);
        _grantRole(UPGRADER_ROLE, _admin);

        globalSettings = _settings;
    }

    function initializeCurve(
        address token,
        uint256 supply,
        uint256 startPrice,
        uint256 targetMarketCap
    ) external onlyRole(FACTORY_ROLE) {
        if (isTokenActive[token]) revert BondingCurve__InvalidParameters();
        if (token == address(0) || supply == 0 || startPrice == 0 || targetMarketCap == 0) {
            revert BondingCurve__InvalidParameters();
        }

        BondingCurveMath.CurveConfig memory config = BondingCurveMath.createPumpFunConfig(
            startPrice,
            targetMarketCap,
            supply
        );

        curveParams[token] = CurveParams({
            startPrice: startPrice,
            targetMarketCap: targetMarketCap,
            currentMarketCap: 0,
            totalSupply: supply,
            availableSupply: supply,
            reserveETH: 0,
            isGraduated: false
        });

        curveConfigs[token] = config;

        tokenIndex[token] = activeTokens.length;
        activeTokens.push(token);
        isTokenActive[token] = true;

        tokenStats[token].allTimeLow = startPrice;
        tokenStats[token].lastTradeTime = block.timestamp;
        
        tokenGraduationDeadline[token] = block.timestamp + 90 days;

        emit CurveInitialized(token, supply, startPrice, targetMarketCap, config.curveType);
    }

    function buy(
        address token,
        uint256 minTokensOut
    ) external payable nonReentrant whenNotPaused onlyActiveToken(token) notBlacklisted checkDailyLimit(msg.value) returns (uint256 tokensOut) {
        if (msg.value < MIN_PURCHASE) revert BondingCurve__InsufficientETH();

        CurveParams storage params = curveParams[token];
        BondingCurveMath.CurveConfig memory config = curveConfigs[token];

        uint256 currentSupply = params.totalSupply - params.availableSupply;
        tokensOut = BondingCurveMath.calculateTokensOut(config, currentSupply, msg.value);

        if (tokensOut == 0 || tokensOut < minTokensOut) revert BondingCurve__SlippageExceeded();
        if (tokensOut > params.availableSupply) revert BondingCurve__InsufficientTokens();

        uint256 priceImpact = _calculatePriceImpact(token, tokensOut, true);
        if (priceImpact > globalSettings.maxPriceImpact) revert BondingCurve__PriceImpactTooHigh();

        uint256 tradingFee = (msg.value * globalSettings.tradingFeeRate) / BASIS_POINTS;
        uint256 protocolFee = (msg.value * globalSettings.protocolFeeRate) / BASIS_POINTS;
        uint256 totalFee = tradingFee + protocolFee;
        uint256 netETH = msg.value - totalFee;

        params.availableSupply -= tokensOut;
        params.reserveETH += netETH;
        params.currentMarketCap = BondingCurveMath.calculateMarketCap(config, currentSupply + tokensOut);
        
        userContributions[token][msg.sender] += msg.value;

        IERC20(token).safeTransfer(msg.sender, tokensOut);

        if (totalFee > 0 && globalSettings.feeRecipient != address(0)) {
            payable(globalSettings.feeRecipient).transfer(totalFee);
        }

        _updateStats(token, msg.sender, tokensOut, msg.value, true, totalFee);

        if (_checkGraduation(token)) {
            emit TokenGraduationReady(token, params.currentMarketCap);
        }

        uint256 newPrice = getCurrentPrice(token);

        emit TokenTraded(token, msg.sender, true, tokensOut, msg.value, newPrice, priceImpact, totalFee);
    }

    function sell(
        address token,
        uint256 tokenAmount,
        uint256 minETHOut
    ) external nonReentrant whenNotPaused onlyActiveToken(token) notBlacklisted returns (uint256 ethOut) {
        if (tokenAmount == 0) revert BondingCurve__InsufficientTokens();

        CurveParams storage params = curveParams[token];
        BondingCurveMath.CurveConfig memory config = curveConfigs[token];

        if (IERC20(token).balanceOf(msg.sender) < tokenAmount) revert BondingCurve__InsufficientTokens();

        SellCalculation memory calc;
        calc.currentSupply = params.totalSupply - params.availableSupply;
        calc.ethOut = BondingCurveMath.calculateETHOut(config, calc.currentSupply, tokenAmount);

        if (calc.ethOut == 0 || calc.ethOut < minETHOut) revert BondingCurve__SlippageExceeded();
        if (calc.ethOut > params.reserveETH) revert BondingCurve__InsufficientETH();

        calc.priceImpact = _calculatePriceImpact(token, tokenAmount, false);
        if (calc.priceImpact > globalSettings.maxPriceImpact) revert BondingCurve__PriceImpactTooHigh();

        calc.tradingFee = (calc.ethOut * globalSettings.tradingFeeRate) / BASIS_POINTS;
        calc.protocolFee = (calc.ethOut * globalSettings.protocolFeeRate) / BASIS_POINTS;
        calc.totalFee = calc.tradingFee + calc.protocolFee;
        calc.netETH = calc.ethOut - calc.totalFee;

        params.availableSupply += tokenAmount;
        params.reserveETH -= calc.ethOut;
        params.currentMarketCap = BondingCurveMath.calculateMarketCap(config, calc.currentSupply - tokenAmount);

        IERC20(token).safeTransferFrom(msg.sender, address(this), tokenAmount);
        payable(msg.sender).transfer(calc.netETH);

        if (calc.totalFee > 0 && globalSettings.feeRecipient != address(0)) {
            payable(globalSettings.feeRecipient).transfer(calc.totalFee);
        }

        _updateStats(token, msg.sender, tokenAmount, calc.ethOut, false, calc.totalFee);

        calc.newPrice = getCurrentPrice(token);

        emit TokenTraded(token, msg.sender, false, tokenAmount, calc.ethOut, calc.newPrice, calc.priceImpact, calc.totalFee);

        ethOut = calc.netETH;
    }

    function getCurrentPrice(address token) public view returns (uint256) {
        if (!isTokenActive[token]) return 0;

        CurveParams memory params = curveParams[token];
        BondingCurveMath.CurveConfig memory config = curveConfigs[token];

        uint256 currentSupply = params.totalSupply - params.availableSupply;
        return BondingCurveMath.calculatePrice(config, currentSupply);
    }

    function getMarketCap(address token) external view returns (uint256) {
        return curveParams[token].currentMarketCap;
    }

    function canGraduate(address token) public view returns (bool) {
        if (!isTokenActive[token]) return false;
        return _checkGraduation(token);
    }

    function getBuyQuote(address token, uint256 ethAmount) external view returns (
        uint256 tokensOut,
        uint256 priceImpact,
        uint256 newPrice,
        uint256 totalFee
    ) {
        if (!isTokenActive[token] || ethAmount == 0) return (0, 0, 0, 0);

        CurveParams memory params = curveParams[token];
        BondingCurveMath.CurveConfig memory config = curveConfigs[token];

        uint256 currentSupply = params.totalSupply - params.availableSupply;
        tokensOut = BondingCurveMath.calculateTokensOut(config, currentSupply, ethAmount);

        if (tokensOut > 0) {
            priceImpact = _calculatePriceImpact(token, tokensOut, true);
            newPrice = BondingCurveMath.calculatePrice(config, currentSupply + tokensOut);
            totalFee = (ethAmount * (globalSettings.tradingFeeRate + globalSettings.protocolFeeRate)) / BASIS_POINTS;
        }
    }

    function getSellQuote(address token, uint256 tokenAmount) external view returns (
        uint256 ethOut,
        uint256 priceImpact,
        uint256 newPrice,
        uint256 totalFee
    ) {
        if (!isTokenActive[token] || tokenAmount == 0) return (0, 0, 0, 0);

        CurveParams memory params = curveParams[token];
        BondingCurveMath.CurveConfig memory config = curveConfigs[token];

        uint256 currentSupply = params.totalSupply - params.availableSupply;
        if (tokenAmount > currentSupply) return (0, 0, 0, 0);

        ethOut = BondingCurveMath.calculateETHOut(config, currentSupply, tokenAmount);

        if (ethOut > 0) {
            priceImpact = _calculatePriceImpact(token, tokenAmount, false);
            newPrice = BondingCurveMath.calculatePrice(config, currentSupply - tokenAmount);
            totalFee = (ethOut * (globalSettings.tradingFeeRate + globalSettings.protocolFeeRate)) / BASIS_POINTS;
        }
    }

    function _calculatePriceImpact(address token, uint256 amount, bool isBuy) internal view returns (uint256) {
        CurveParams memory params = curveParams[token];
        BondingCurveMath.CurveConfig memory config = curveConfigs[token];

        uint256 currentSupply = params.totalSupply - params.availableSupply;
        uint256 currentPrice = BondingCurveMath.calculatePrice(config, currentSupply);

        uint256 newSupply = isBuy ? currentSupply + amount : currentSupply - amount;
        uint256 newPrice = BondingCurveMath.calculatePrice(config, newSupply);

        if (currentPrice == 0) return 0;

        uint256 priceDiff = newPrice > currentPrice ? newPrice - currentPrice : currentPrice - newPrice;
        return (priceDiff * BASIS_POINTS) / currentPrice;
    }

    function _checkGraduation(address token) internal view returns (bool) {
        CurveParams memory params = curveParams[token];
        return params.currentMarketCap >= params.targetMarketCap;
    }

    function _updateStats(
        address token,
        address user,
        uint256 tokenAmount,
        uint256 ethAmount,
        bool isBuy,
        uint256 fee
    ) internal {
        TokenStats storage stats = tokenStats[token];
        UserTokenStats storage userStat = userStats[user][token];

        if (isBuy) {
            stats.totalBuys++;
        } else {
            stats.totalSells++;
        }
        stats.totalVolume += ethAmount;
        stats.totalFees += fee;
        stats.lastTradeTime = block.timestamp;

        uint256 currentPrice = getCurrentPrice(token);
        if (currentPrice > stats.allTimeHigh) {
            stats.allTimeHigh = currentPrice;
        }
        if (stats.allTimeLow == 0 || currentPrice < stats.allTimeLow) {
            stats.allTimeLow = currentPrice;
        }

        if (!userStat.hasTraded) {
            userStat.hasTraded = true;
            userStat.firstBuyTime = block.timestamp;
            stats.uniqueTraders++;
        }

        if (isBuy) {
            userStat.totalBought += tokenAmount;
            userStat.totalSpent += ethAmount;
        } else {
            userStat.totalSold += tokenAmount;
            userStat.totalReceived += ethAmount;
        }
        userStat.lastTradeTime = block.timestamp;
    }

    function _checkDailyLimit(address user, uint256 ethAmount) internal {
        if (userLastReset[user] + 1 days < block.timestamp) {
            userDailyVolume[user] = 0;
            userLastReset[user] = block.timestamp;
        }

        userDailyVolume[user] += ethAmount;

        uint256 dailyLimit = 10 ether;
        if (userDailyVolume[user] > dailyLimit) {
            revert BondingCurve__DailyLimitExceeded();
        }
    }

    function updateGlobalSettings(GlobalSettings calldata settings) external onlyRole(ADMIN_ROLE) {
        globalSettings = settings;
        emit GlobalSettingsUpdated(settings);
    }

    function setUserBlacklist(address user, bool blacklisted) external onlyRole(ADMIN_ROLE) {
        userBlacklist[user] = blacklisted;
    }

    function updateCurveParams(
        address token,
        uint256 newSupply,
        uint256 newStartPrice,
        uint256 newTargetMarketCap
    ) external onlyRole(ADMIN_ROLE) {
        if (!isTokenActive[token]) revert BondingCurve__TokenNotInitialized();
        if (newSupply == 0 || newStartPrice == 0 || newTargetMarketCap == 0) {
            revert BondingCurve__InvalidParameters();
        }

        CurveParams storage params = curveParams[token];
        
        uint256 soldSupply = params.totalSupply - params.availableSupply;
        
        if (newSupply < soldSupply) revert BondingCurve__InvalidParameters();
        
        params.totalSupply = newSupply;
        params.availableSupply = newSupply - soldSupply;
        params.startPrice = newStartPrice;
        params.targetMarketCap = newTargetMarketCap;
        
        BondingCurveMath.CurveConfig memory newConfig = BondingCurveMath.createPumpFunConfig(
            newStartPrice,
            newTargetMarketCap,
            newSupply
        );
        curveConfigs[token] = newConfig;
        
        params.currentMarketCap = BondingCurveMath.calculateMarketCap(newConfig, soldSupply);
        
        emit CurveParamsUpdated(token, newSupply, newStartPrice, newTargetMarketCap);
    }

    function getCurveParams(address token) external view returns (CurveParams memory) {
        return curveParams[token];
    }

    function graduateToken(address token) external returns (bool) {
        if (msg.sender != globalSettings.graduationManager) revert BondingCurve__NotAuthorized();
        if (!canGraduate(token)) return false;

        curveParams[token].isGraduated = true;

        uint256 index = tokenIndex[token];
        uint256 lastIndex = activeTokens.length - 1;

        if (index != lastIndex) {
            address lastToken = activeTokens[lastIndex];
            activeTokens[index] = lastToken;
            tokenIndex[lastToken] = index;
        }

        activeTokens.pop();
        delete tokenIndex[token];
        isTokenActive[token] = false;

        return true;
    }

    function extendDeadline(address token, uint256 additionalTime) external onlyRole(ADMIN_ROLE) {
        if (!isTokenActive[token]) revert BondingCurve__TokenNotInitialized();
        if (tokenFailed[token]) revert BondingCurve__TokenFailed();
        
        tokenGraduationDeadline[token] += additionalTime;
    }
    
    function markTokenAsFailed(address token) external {
        if (!isTokenActive[token]) revert BondingCurve__TokenNotInitialized();
        if (tokenFailed[token]) revert BondingCurve__TokenFailed();
        if (curveParams[token].isGraduated) revert BondingCurve__TokenAlreadyGraduated();
        if (block.timestamp < tokenGraduationDeadline[token]) revert BondingCurve__DeadlineNotReached();
        
        if (_checkGraduation(token)) revert BondingCurve__InvalidParameters();
        
        tokenFailed[token] = true;
        
        emit TokenFailed(token, tokenGraduationDeadline[token], curveParams[token].reserveETH);
    }
    
    function approveRefund(address token) external onlyRole(ADMIN_ROLE) {
        if (!tokenFailed[token]) revert BondingCurve__InvalidParameters();
        
        refundApproved[token] = true;
        
        emit RefundApproved(token, block.timestamp);
    }
    
    function claimRefund(address token) external nonReentrant {
        if (!tokenFailed[token]) revert BondingCurve__InvalidParameters();
        if (!refundApproved[token]) revert BondingCurve__RefundNotApproved();
        
        uint256 contribution = userContributions[token][msg.sender];
        if (contribution == 0) revert BondingCurve__NoContribution();
        
        userContributions[token][msg.sender] = 0;
        
        uint256 adminFee = (contribution * 2000) / BASIS_POINTS;
        uint256 refundAmount = contribution - adminFee;
        
        uint256 userTokenBalance = IERC20(token).balanceOf(msg.sender);
        if (userTokenBalance > 0) {
            IERC20(token).safeTransferFrom(msg.sender, address(this), userTokenBalance);
        }
        
        payable(msg.sender).transfer(refundAmount);
        
        if (adminFee > 0 && globalSettings.feeRecipient != address(0)) {
            payable(globalSettings.feeRecipient).transfer(adminFee);
        }
        
        emit RefundClaimed(token, msg.sender, refundAmount, adminFee);
    }
    
    function getDeadline(address token) external view returns (uint256) {
        return tokenGraduationDeadline[token];
    }
    
    function getTimeUntilDeadline(address token) external view returns (uint256) {
        if (block.timestamp >= tokenGraduationDeadline[token]) return 0;
        return tokenGraduationDeadline[token] - block.timestamp;
    }
    
    function getUserContribution(address token, address user) external view returns (uint256) {
        return userContributions[token][user];
    }

    function emergencyWithdraw(address to) external onlyRole(ADMIN_ROLE) {
        if (to == address(0)) revert BondingCurve__InvalidParameters();
        uint256 balance = address(this).balance;
        if (balance > 0) {
            payable(to).transfer(balance);
        }
    }

    function _authorizeUpgrade(address newImplementation) internal view override onlyRole(UPGRADER_ROLE) {
        newImplementation;
    }
}
"
    },
    "laxwin contracts/BondingCurveMath.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

library BondingCurveMath {

    uint256 public constant BASIS_POINTS = 10000;
    uint256 public constant PRECISION = 1e18;
    uint256 public constant MAX_SUPPLY = 1e15;
    
    uint256 public constant DEFAULT_MAX_SUPPLY = 1e28;
    uint256 public constant MIN_START_PRICE = 1e9;
    uint256 public constant MAX_TARGET_MARKET_CAP = 100000 ether;
    
    uint256 public constant ABSOLUTE_MAX_SUPPLY = 1e32;

    error BondingCurve__InvalidParameters();
    error BondingCurve__InsufficientSupply();
    error BondingCurve__PriceCalculationFailed();
    error BondingCurve__Overflow();

    enum CurveType {
        LINEAR,
        EXPONENTIAL,
        LOGARITHMIC,
        SQUARE_ROOT,
        QUADRATIC
    }

    struct CurveConfig {
        CurveType curveType;
        uint256 a;
        uint256 b;
        uint256 c;
        uint256 startPrice;
        uint256 targetPrice;
        uint256 maxSupply;
    }

    function calculatePrice(
        CurveConfig memory config,
        uint256 currentSupply
    ) internal pure returns (uint256 price) {
        if (currentSupply > config.maxSupply) revert BondingCurve__InsufficientSupply();

        if (config.curveType == CurveType.LINEAR) {
            price = _calculateLinearPrice(config, currentSupply);
        } else if (config.curveType == CurveType.EXPONENTIAL) {
            price = _calculateExponentialPrice(config, currentSupply);
        } else if (config.curveType == CurveType.LOGARITHMIC) {
            price = _calculateLogarithmicPrice(config, currentSupply);
        } else if (config.curveType == CurveType.SQUARE_ROOT) {
            price = _calculateSquareRootPrice(config, currentSupply);
        } else if (config.curveType == CurveType.QUADRATIC) {
            price = _calculateQuadraticPrice(config, currentSupply);
        } else {
            revert BondingCurve__InvalidParameters();
        }

        if (price == 0) revert BondingCurve__PriceCalculationFailed();
    }

    function calculateTokensOut(
        CurveConfig memory config,
        uint256 currentSupply,
        uint256 ethAmount
    ) internal pure returns (uint256 tokensOut) {
        if (ethAmount == 0) return 0;

        uint256 low = 0;
        uint256 high = config.maxSupply - currentSupply;
        uint256 tolerance = PRECISION / 1000;

        while (high - low > tolerance && high > low) {
            uint256 mid = (low + high) / 2;
            uint256 cost = calculateCost(config, currentSupply, mid);

            if (cost < ethAmount) {
                low = mid;
            } else if (cost > ethAmount) {
                high = mid;
            } else {
                return mid;
            }
        }

        tokensOut = low;
    }

    function calculateCost(
        CurveConfig memory config,
        uint256 currentSupply,
        uint256 tokenAmount
    ) internal pure returns (uint256 cost) {
        if (tokenAmount == 0) return 0;
        if (currentSupply + tokenAmount > config.maxSupply) {
            revert BondingCurve__InsufficientSupply();
        }

        cost = _calculateIntegral(config, currentSupply, currentSupply + tokenAmount);
    }

    function calculateETHOut(
        CurveConfig memory config,
        uint256 currentSupply,
        uint256 tokenAmount
    ) internal pure returns (uint256 ethOut) {
        if (tokenAmount == 0) return 0;
        if (tokenAmount > currentSupply) revert BondingCurve__InsufficientSupply();

        ethOut = _calculateIntegral(config, currentSupply - tokenAmount, currentSupply);
    }

    function calculateMarketCap(
        CurveConfig memory config,
        uint256 currentSupply
    ) internal pure returns (uint256 marketCap) {
        uint256 currentPrice = calculatePrice(config, currentSupply);
        
        if (currentSupply > type(uint256).max / currentPrice) {
            revert BondingCurve__Overflow();
        }
        
        marketCap = (currentSupply * currentPrice) / PRECISION;
    }

    function _calculateLinearPrice(
        CurveConfig memory config,
        uint256 supply
    ) internal pure returns (uint256) {

        return config.startPrice + (config.a * supply) / PRECISION;
    }

    function _calculateExponentialPrice(
        CurveConfig memory config,
        uint256 supply
    ) internal pure returns (uint256) {

        uint256 rate = config.a;
        uint256 multiplier = PRECISION + (rate * supply) / config.maxSupply;
        return (config.startPrice * multiplier) / PRECISION;
    }

    function _calculateLogarithmicPrice(
        CurveConfig memory config,
        uint256 supply
    ) internal pure returns (uint256) {
        if (supply == 0) return config.startPrice;

        uint256 logValue = _approximateLog(supply + PRECISION);
        return config.startPrice + (config.a * logValue) / PRECISION;
    }

    function _calculateSquareRootPrice(
        CurveConfig memory config,
        uint256 supply
    ) internal pure returns (uint256) {

        uint256 sqrtValue = _sqrt(supply * PRECISION);
        return config.startPrice + (config.a * sqrtValue) / PRECISION;
    }

    function _calculateQuadraticPrice(
        CurveConfig memory config,
        uint256 supply
    ) internal pure returns (uint256) {

        uint256 term1 = (config.a * supply * supply) / (PRECISION * PRECISION);
        uint256 term2 = (config.b * supply) / PRECISION;
        return term1 + term2 + config.c;
    }

    function _calculateIntegral(
        CurveConfig memory config,
        uint256 from,
        uint256 to
    ) internal pure returns (uint256 integral) {
        if (from >= to) return 0;

        if (config.curveType == CurveType.LINEAR) {
            
            uint256 diff = to - from;
            uint256 sum = to + from;
            
            uint256 term1_numerator = _safeMul(config.a, sum);
            uint256 term1 = term1_numerator / (2 * PRECISION);
            
            uint256 term2 = config.startPrice;
            
            uint256 avgPrice = term1 + term2;
            
            integral = _safeMul(diff, avgPrice) / PRECISION;
            
        } else {
            integral = _numericalIntegration(config, from, to);
        }
    }

    function _numericalIntegration(
        CurveConfig memory config,
        uint256 from,
        uint256 to
    ) internal pure returns (uint256 integral) {
        uint256 n = 100;
        uint256 h = (to - from) / n;

        uint256 sum = calculatePrice(config, from) + calculatePrice(config, to);

        for (uint256 i = 1; i < n; i++) {
            uint256 x = from + i * h;
            uint256 price = calculatePrice(config, x);
            sum += (i % 2 == 0) ? 2 * price : 4 * price;
        }

        integral = (sum * h) / (3 * PRECISION);
    }

    function _sqrt(uint256 x) internal pure returns (uint256) {
        if (x == 0) return 0;

        uint256 z = (x + 1) / 2;
        uint256 y = x;

        while (z < y) {
            y = z;
            z = (x / z + z) / 2;
        }

        return y;
    }

    function _approximateLog(uint256 x) internal pure returns (uint256) {
        if (x <= PRECISION) return 0;

        uint256 result = 0;

        while (x >= 2 * PRECISION) {
            x = x / 2;
            result += 693147180559945309;
        }

        if (x > PRECISION) {
            uint256 y = x - PRECISION;
            result += (y * PRECISION) / x;
        }

        return result;
    }

    function createPumpFunConfig(
        uint256 startPrice,
        uint256 targetMarketCap,
        uint256 maxSupply
    ) internal pure returns (CurveConfig memory) {
        if (targetMarketCap == 0 || maxSupply == 0 || startPrice == 0) {
            revert BondingCurve__InvalidParameters();
        }
        
        if (maxSupply > ABSOLUTE_MAX_SUPPLY) revert BondingCurve__Overflow();
        if (startPrice < MIN_START_PRICE) revert BondingCurve__InvalidParameters();
        
        uint256 targetPrice;
        
        if (targetMarketCap > type(uint256).max / PRECISION) {
            targetPrice = (targetMarketCap / maxSupply) * PRECISION;
        } else {
            targetPrice = (targetMarketCap * PRECISION) / maxSupply;
        }
        
        if (targetPrice <= startPrice) {
            revert BondingCurve__InvalidParameters();
        }
        
        uint256 priceDiff = targetPrice - startPrice;
        uint256 a;
        
        if (priceDiff > type(uint256).max / PRECISION) {
            a = (priceDiff / maxSupply) * PRECISION;
        } else {
            a = (priceDiff * PRECISION) / maxSupply;
        }

        return CurveConfig({
            curveType: CurveType.LINEAR,
            a: a,
            b: 0,
            c: 0,
            startPrice: startPrice,
            targetPrice: targetPrice,
            maxSupply: maxSupply
        });
    }
    
    function _safeMul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        if (c / a != b) revert BondingCurve__Overflow();
        return c;
    }
    
    function _safeDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) revert BondingCurve__InvalidParameters();
        return a / b;
    }
}
"
    },
    "laxwin contracts/ILaxcePadInterfaces.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface ITokenFactory {
    struct TokenParams {
        string name;
        string symbol;
        string description;
        string imageUrl;
        string[] socialLinks;
        uint256 totalSupply;
        uint256 bondingCurveSupply;
        uint256 liquiditySupply;
        uint256 startPrice;
        uint256 targetMarketCap;
    }

    struct SupplyLimits {
        uint256 minTotalSupply;
        uint256 maxTotalSupply;
        uint256 minBondingCurvePercent;
        uint256 maxBondingCurvePercent;
        uint256 minStartPrice;
        uint256 maxStartPrice;
        uint256 minTargetMarketCap;
        uint256 maxTargetMarketCap;
    }

    function createToken(TokenParams calldata params) external payable returns (address token);
    function getTokenInfo(address token) external view returns (TokenParams memory);
    function isTokenCreated(address token) external view returns (bool);
    function getSupplyLimits() external view returns (SupplyLimits memory);
}

interface IBondingCurve {
    struct CurveParams {
        uint256 startPrice;
        uint256 targetMarketCap;
        uint256 currentMarketCap;
        uint256 totalSupply;
        uint256 availableSupply;
        uint256 reserveETH;
        bool isGraduated;
    }

    function initializeCurve(
        address token,
        uint256 supply,
        uint256 startPrice,
        uint256 targetMarketCap
    ) external;

    function updateCurveParams(
        address token,
        uint256 newSupply,
        uint256 newStartPrice,
        uint256 newTargetMarketCap
    ) external;

    function buy(address token, uint256 minTokensOut) external payable returns (uint256 tokensOut);
    function sell(address token, uint256 tokenAmount, uint256 minETHOut) external returns (uint256 ethOut);

    function getCurrentPrice(address token) external view returns (uint256);
    function getMarketCap(address token) external view returns (uint256);
    function canGraduate(address token) external view returns (bool);
    function graduateToken(address token) external returns (bool);
    function getCurveParams(address token) external view returns (CurveParams memory);

    event TokenBought(address indexed token, address indexed buyer, uint256 ethAmount, uint256 tokenAmount, uint256 newPrice);
    event TokenSold(address indexed token, address indexed seller, uint256 tokenAmount, uint256 ethAmount, uint256 newPrice);
    event CurveInitialized(address indexed token, uint256 supply, uint256 startPrice, uint256 targetMarketCap);
    event CurveParamsUpdated(address indexed token, uint256 supply, uint256 startPrice, uint256 targetMarketCap);
}

interface IGraduationManager {
    function graduateToken(address token) external returns (address pool);
    function isGraduated(address token) external view returns (bool);
    function getGraduatedPool(address token) external view returns (address);

    event TokenGraduated(address indexed token, address indexed pool, uint256 marketCap, uint256 liquidityAdded);
}

interface IRevenueDistribution {
    struct RevenueShare {
        address recipient;
        uint256 percentage;
        string description;
    }

    function distributeRevenue() external;
    function setRevenueShare(address recipient, uint256 percentage, string calldata description) external;
    function getRevenueShare(address recipient) external view returns (uint256);
    function getTotalRevenue() external view returns (uint256);

    event RevenueDistributed(uint256 totalAmount, uint256 timestamp);
    event RevenueShareUpdated(address indexed recipient, uint256 percentage);
}

interface ILaxcePadToken {
    function mint(address to, uint256 amount) external;
    function burn(uint256 amount) external;
    function setMetadata(string calldata description, string calldata imageUrl, string[] calldata socialLinks) external;
    function getMetadata() external view returns (string memory description, string memory imageUrl, string[] memory socialLinks);
    function creator() external view returns (address);
    function createdAt() external view returns (uint256);
}

interface IDEXIntegration {
    function getTokenRegistry() external view returns (address);
    function getPoolFactory() external view returns (address);
    function getDEXEngine() external view returns (address);
    function getCoreRegistry() external view returns (address);
}
"
    },
    "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}
"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
"
    },
    "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable
    struct PausableStorage {
        bool _paused;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;

    function _getPausableStorage() private pure returns (PausableStorage storage $) {
        assembly {
            $.slot := PausableStorageLocation
        }
    }

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    function __Pausable_init() internal onlyInitializing {
    }

    function __Pausable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        PausableStorage storage $ = _getPausableStorage();
        return $._paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = false;
        emit Unpaused(_msgSender());
    }
}
"
    },
    "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 role => RoleData) _roles;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;

    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        AccessControlStorage storage $ = _getAccessControlStorage();
        bytes32 previousAdminRole = getRoleAdmin(role);
        $._roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (!hasRole(role, account)) {
            $._roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (hasRole(role, account)) {
            $._roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
"
    },
    "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppe

Tags:
ERC20, ERC165, Proxy, Mintable, Burnable, Liquidity, Upgradeable, Factory|addr:0xe2a094699e60fdcfebb458f6de6dcbac7e085d6e|verified:true|block:23646412|tx:0x2ecedb5b6fa433acb0face636ab915f563534fe8de5ef985e21df3e23f4deea3|first_check:1761326002

Submitted on: 2025-10-24 19:13:23

Comments

Log in to comment.

No comments yet.