Skip to main content
PulseScanner.io

Address

0x6dcfb4ed7b9aa0bf032e9c8f37ed066bd52cf27c
Current Holdings
$0.00
TXs sent
not counted
First Active
2026-05-22
block 26,597,715
Last Active
30 days ago
block 27,309,744
Funded By
0xd8ba…40c0

Net worth historyi

7 snapshots · to block 27,522,600coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchPlsxSmartTokensolc 0.8.35+commit.47b9deddruntime exact · creation not verified
// SPDX-License-Identifier: MIT
//
// Plsx Forge — tax-token launcher (fork of Icaria Forge for plsx.fun)
// Web: https://plsx.fun
//
pragma solidity ^0.8.20;

import { PlsxSmartToken } from "./PlsxSmartToken.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IPlsxHelpers } from "./interfaces/IPlsxHelpers.sol";

// --- Custom errors for gas & bytecode savings ---
error Denied();
error InsufficientPayment();
error NotFactoryToken();
error FeeTooHigh();
error InvalidAddress();
error WalletExists();
error WalletsEmpty();
error InvalidAmount();
error InvalidInput();
error LowAmount();
error TransferFailed();

contract PlsxSmartTokenFactory is Ownable, ReentrancyGuard {
    uint256 public constant GLOBAL_DIVIDER = 10000;

    // plsx.fun platform fee taken from each token's total taxes.
    // 45 / 10000 = 0.45% (matches Icaria). E.g. if a token's total tax is 1%,
    // the platform slice is 0.0045%. Adjust with setPlsxfunFee.
    uint256 public PLSXFUN_FEE = 45;

    // Single wallet that receives ALL platform fees — hardcoded so a deploy
    // can never misroute them: the PLS creation fee (distributionWallets), the
    // token tax slice (PLSXFUN_WALLET), and any processPLS sweeps
    // (processorWallet) all default to this address in the constructor.
    address public constant FEE_WALLET = 0x5Cd66b653c3973B3A82453eba5D07F56F5c1e8ac;

    // Wallet that receives the platform's tax slice (was ICARIA_WALLET in the
    // upstream Icaria Forge). The created token reads this via the factory so
    // its non-accumulated platform fee is routed here. Defaults to FEE_WALLET.
    address public PLSXFUN_WALLET;

    address public manager;
    uint256 public tokenCreationPrice;
    address public helpersAddress;

    mapping(address => bool) public isFactoryToken;

    // Wallets that split the PLS creation fee paid per taxed token.
    address processorWallet;
    address[] public distributionWallets;

    event TokenCreated(address indexed tokenAddress, string name, string symbol, address indexed owner);

    modifier onlyManager() {
        if(!(owner() == _msgSender() || manager == _msgSender() || processorWallet == _msgSender())) revert Denied();
        _;
    }

    // No distribution-wallets param — ALL fee sinks are locked to FEE_WALLET
    // on deploy so fees can't be misrouted. The owner can still rebalance
    // later via setProcessorWallet / setPlsxfunWallet / add/removeDistributionWallet.
    constructor(uint256 _tokenCreationPrice, address _helpersAddress) Ownable(msg.sender) {
        tokenCreationPrice = _tokenCreationPrice;
        helpersAddress = _helpersAddress;
        PLSXFUN_WALLET = FEE_WALLET;        // platform tax slice
        processorWallet = FEE_WALLET;       // processPLS sweeps
        distributionWallets.push(FEE_WALLET); // PLS creation fee
    }

    // NOTE: ownership-renounce and trading-enabled are NOT caller options on
    // the plsx.fun fork — they're enforced unconditionally below. Every token
    // forged here ships ownerless (deployer can't change taxes / mint / rug)
    // and with trading already live. The upstream `ownershipRenounced` and
    // `_tradingEnabled` params were removed so there's no way to pass `false`.
    function createToken(
        string memory name_,
        string memory symbol_,
        uint256 _initialSupply,
        IPlsxHelpers.Tax[] memory _taxes,
        address _plsxSmartTrader
    ) external payable nonReentrant returns (address) {
        if (_taxes.length > 0) {
            if(msg.value < tokenCreationPrice) revert InsufficientPayment();
        }

        PlsxSmartToken newToken = new PlsxSmartToken(
            name_,
            symbol_,
            address(this),
            msg.sender,
            _initialSupply,
            _taxes,
            _plsxSmartTrader,
            address(this),
            helpersAddress,
            true // _tradingEnabled — always on, not caller-selectable
        );

        isFactoryToken[address(newToken)] = true;
        // Always renounce — not caller-selectable.
        newToken.renounceOwnership();
        if (_taxes.length > 0 && tokenCreationPrice > 0) {
            _withdrawPLS(tokenCreationPrice);
        }
        emit TokenCreated(address(newToken), name_, symbol_, msg.sender);
        return address(newToken);
    }

    function getTokenTaxData(address tokenAddress) external view returns (IPlsxHelpers.Tax[] memory) {
        if(!isFactoryToken[tokenAddress]) revert NotFactoryToken();
        return PlsxSmartToken(payable(tokenAddress)).getTaxes();
    }

    function getTokenData(address tokenAddress) external view returns (
        string memory name,
        string memory symbol,
        uint256 initialSupply,
        uint256 currentSupply,
        bool ownershipRenounced,
        IPlsxHelpers.Tax[] memory taxes,
        bool tradingEnabled
    ) {
        if(!isFactoryToken[tokenAddress]) revert NotFactoryToken();
        PlsxSmartToken token = PlsxSmartToken(payable(tokenAddress));

        name = token.name();
        symbol = token.symbol();
        initialSupply = token.initialSupply();
        currentSupply = token.totalSupply();
        ownershipRenounced = token.owner() == address(0);
        taxes = token.getTaxes();
        tradingEnabled = token.tradingEnabled();
        return (name, symbol, initialSupply, currentSupply, ownershipRenounced, taxes, tradingEnabled);
    }

    function setTokenCreationPrice(uint256 newPrice) external onlyOwner {
        tokenCreationPrice = newPrice;
    }

    function setPlsxfunFee(uint256 newFee) external onlyOwner {
        if(newFee > GLOBAL_DIVIDER) revert FeeTooHigh();
        PLSXFUN_FEE = newFee;
    }

    function setPlsxfunWallet(address wallet) external onlyOwner {
        if(wallet == address(0)) revert InvalidAddress();
        PLSXFUN_WALLET = wallet;
    }

    function setProcessorWallet(address wallet) external onlyOwner {
        if(wallet == address(0)) revert InvalidAddress();
        processorWallet = wallet;
    }

    function addDistributionWallet(address wallet) external onlyOwner {
        if(wallet == address(0)) revert InvalidAddress();

        for(uint256 i = 0; i < distributionWallets.length; i++) {
            if(distributionWallets[i] == wallet) {
                revert WalletExists();
            }
        }

        distributionWallets.push(wallet);
    }

    function removeDistributionWallet(address walletToRemove) external onlyOwner {
        if(distributionWallets.length == 0) revert WalletsEmpty();

        for(uint256 i = 0; i < distributionWallets.length; i++) {
            if(distributionWallets[i] == walletToRemove) {
                if (i != distributionWallets.length - 1) {
                    distributionWallets[i] = distributionWallets[distributionWallets.length - 1];
                }
                distributionWallets.pop();
                return;
            }
        }
        revert();
    }

    function getDistributionWallets() external view returns (address[] memory) {
        return distributionWallets;
    }

    function processPLS(uint256 amount) external onlyManager {
        if(amount == 0 || amount > address(this).balance) revert InvalidAmount();
        (bool success, ) = processorWallet.call{value: amount}("");
    }

    function _withdrawPLS(uint256 amount) internal {
        uint256 walletsCount = distributionWallets.length;
        if(!(walletsCount > 0 && amount > 0 && amount <= address(this).balance)) revert InvalidInput();
        uint256 amountPerWallet = amount / walletsCount;
        if(amountPerWallet == 0) revert LowAmount();

        for(uint256 i = 0; i < walletsCount; i++) {
            (bool success, ) = distributionWallets[i].call{value: amountPerWallet}("");
        }
    }

    function withdrawPLS(uint256 amount) external onlyManager nonReentrant {
       _withdrawPLS(amount);
    }

    function setManager(address newManager) external onlyOwner {
        manager = newManager;
    }

    function withdrawERC20(address tokenAddress, address to) external onlyManager nonReentrant {
        if(tokenAddress == address(0)) revert InvalidAddress();

        IERC20 token = IERC20(tokenAddress);
        uint256 balance = token.balanceOf(address(this));
        if(!token.transfer(to, balance)) revert TransferFailed();
    }

    receive() external payable {}
}