S Price: $0.724798 (+7.70%)

Contract Diff Checker

Contract Name:
BRNx

Contract Source Code:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

abstract contract Ownable is Context {
    address private _owner;

    error OwnableUnauthorizedAccount(address account);
    error OwnableInvalidOwner(address owner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

abstract contract ReentrancyGuard {
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

interface IERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 value) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

interface IERC20Metadata is IERC20 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
}

interface IERC20Errors {
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
    error ERC20InvalidSender(address sender);
    error ERC20InvalidReceiver(address receiver);
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
    error ERC20InvalidApprover(address approver);
    error ERC20InvalidSpender(address spender);
}

abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    function name() public view virtual returns (string memory) {
        return _name;
    }

    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

interface IV3SwapRouter {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        address recipient;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 limitSqrtPrice;
    }
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}

interface INonfungiblePositionManager {
    function createAndInitializePoolIfNecessary(
        address token0,
        address token1,
        uint160 sqrtPriceX96
        ) external payable returns (address pool);
    struct MintParams {
        address token0;
        address token1;
        int24 tickLower;
        int24 tickUpper;
        uint256 amount0Desired;
        uint256 amount1Desired;
        uint256 amount0Min;
        uint256 amount1Min;
        address recipient;
        uint256 deadline;
    }
    function mint(MintParams calldata params) external payable returns (
            uint256 tokenId,
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        );
}


contract BRNx is ERC20, Ownable, ReentrancyGuard {

    // CONSTANT VARIABLES
    IV3SwapRouter public constant SWAP_ROUTER = IV3SwapRouter(0xA047e2AbF8263FcA7c368F43e2f960A06FD9949f);
    INonfungiblePositionManager public constant NONFUNGIBLE_POSITION_MANAGER = INonfungiblePositionManager(0xd82Fe82244ad01AaD671576202F9b46b76fAdFE2);
    address public constant TOKEN_PAIR_ADDRESS = 0xA04BC7140c26fc9BB1F36B1A604C7A5a88fb0E70; //SWPx
    uint16 public constant BUY_FEES = 600; //6%
    uint16 public constant BURN_SHARE = 400; //4%
    uint16 public constant TREASURY_SHARE = 175; //1.75%
    uint16 public constant CALLER_SHARE = 25; //0.25%
    address private constant DEAD_ADDRESS = address(0xdead);
    
    // OTHER VARIABLES
    bool private swapping;
    address public treasuryWallet;
    address public devWallet;
    address public algebraV3Pair;
    uint256 public minimumBalanceBB;
    uint40 public cooldownPeriodBB;
    bool private limitsInEffect;
    uint256 private maxW;

    // MAPPINGS
    mapping(address => bool) public isExcludedFromFees;
    mapping(address => bool) public automatedMarketMakerPairs;
    mapping(address => uint256) public lastBBCalledTime;

    // DEVWALLET CHANGE TIMELOCK VARIABLES
    struct DevWalletChange {
        address newDevWallet;
        uint256 effectiveTime;
        bool pending;
    }
    DevWalletChange public pendingDevWalletChange;
    uint256 public constant DEV_WALLET_TIMELOCK = 2 days;
    event ChangeDevWallet(address indexed newDevWallet, address oldDevWallet);

    // TREASURYWALLET CHANGE TIMELOCK VARIABLES
    struct TreasuryWalletChange {
        address newTreasuryWallet;
        uint256 effectiveTime;
        bool pending;
    }
    TreasuryWalletChange public pendingTreasuryWalletChange;
    uint256 public constant TREASURY_WALLET_TIMELOCK = 1 days;
    event ChangeTreasuryWallet(address indexed newTreasuryWallet, address oldTreasuryWallet);

    // EVENTS
    event ExcludeFromFees(address indexed account, bool isExcluded);
    event ChangeAutomatedMarketMakerPairs(address indexed automatedMarketMakerPairs, bool isAutomatedMarketMakerPairs);
    event ChangeMinimumBalanceBB(uint256 newMinimumBalanceBB, uint256 oldMinimumBalanceBB);
    event ChangeCooldownPeriodBB(uint40 newCooldownPeriodBB, uint40 oldCooldownPeriodBB);
    event BuyAndBurn(address indexed caller, uint256 amountToBurn, uint256 amountToTreasury, uint256 amountToCaller);
    
    // MODIFIERS
    modifier onlyDev() {
        require(msg.sender == devWallet, "Only the dev can run this function");
        _;
    }

    constructor(
    )
        ERC20("BurnX", "BRNx")
        Ownable(msg.sender)
    {
        devWallet = msg.sender;
        treasuryWallet = 0xF7f259F157481365ba2Eee1B692D29C876180fE2;
        minimumBalanceBB = 1000 * 10**18; // 1000 BRNx
        cooldownPeriodBB = 8 hours;

        uint256 _totalSupply = 50_000_000 * 10**18; // 50M BRNx
        maxW = _totalSupply * 2 / 100;
        limitsInEffect = true;
        
        // exclude from paying fees
        isExcludedFromFees[address(this)] = true;
        isExcludedFromFees[DEAD_ADDRESS] = true;
        isExcludedFromFees[address(NONFUNGIBLE_POSITION_MANAGER)] = true;
        isExcludedFromFees[treasuryWallet] = true;

        _mint(address(this), _totalSupply);

    }


    // OWNER FUNCTIONS
    function mintAndRenounce(uint160 _sqrtPriceX96, int24 _tickLower, int24 _tickUpper) public onlyOwner {

        address token0;
        address token1;
        uint256 amount0Desired;
        uint256 amount1Desired;

        // create a new pair and initialize at a certain price
        if (address(this) < TOKEN_PAIR_ADDRESS) {
            algebraV3Pair = NONFUNGIBLE_POSITION_MANAGER.createAndInitializePoolIfNecessary(address(this), TOKEN_PAIR_ADDRESS, _sqrtPriceX96);
            token0 = address(this);
            token1 = TOKEN_PAIR_ADDRESS;
            amount0Desired = balanceOf(address(this));
            amount1Desired = 0;
        }
        else {
            algebraV3Pair = NONFUNGIBLE_POSITION_MANAGER.createAndInitializePoolIfNecessary(TOKEN_PAIR_ADDRESS, address(this), _sqrtPriceX96);
            token0 = TOKEN_PAIR_ADDRESS;
            token1 = address(this);
            amount0Desired = 0;
            amount1Desired = balanceOf(address(this));
        }

        automatedMarketMakerPairs[algebraV3Pair] = true;

        //addLP automatically
        _approve(address(this), address(NONFUNGIBLE_POSITION_MANAGER), balanceOf(address(this)));

        // build the params to mint
        INonfungiblePositionManager.MintParams memory params;
        params = INonfungiblePositionManager.MintParams({
            token0: token0,
            token1: token1,
            tickLower: _tickLower,
            tickUpper: _tickUpper,
            amount0Desired: amount0Desired,
            amount1Desired: amount1Desired,
            amount0Min: 0,
            amount1Min: 0,
            recipient: devWallet,
            deadline: block.timestamp
        });

        // mint the position
        NONFUNGIBLE_POSITION_MANAGER.mint(params);

        // renounce ownership
        renounceOwnership();

    }


    // DEV FUNCTIONS -> can be run by the dev after renounce in order to manage the project even after the contract is renounced
    function removeLimits() public onlyDev {
        require(limitsInEffect, "Limits were removed already");
     
        limitsInEffect = false;

        // it's gonna call the buyAndBurn function first and send the caller's share to the treasury
        _buyAndBurn(treasuryWallet);   
    }

    function excludeFromFees(address _account, bool _excluded) public onlyDev nonReentrant {
        require(!automatedMarketMakerPairs[_account], "Pool addresses cannot be excluded from fees!");

        isExcludedFromFees[_account] = _excluded;

        emit ExcludeFromFees(_account, _excluded);
    }

    function changeAutomatedMarketMakerPairs(address _automatedMarketMakerPairs, bool _isAutomatedMarketMakerPairs) public onlyDev nonReentrant {
        require(_automatedMarketMakerPairs != address(0), "Automated Market Maker Pair must be a valid address");
        require(_automatedMarketMakerPairs != algebraV3Pair, "Can't remove algebraV3Pair from the Automated Market Maker Pairs!");

        automatedMarketMakerPairs[_automatedMarketMakerPairs] = _isAutomatedMarketMakerPairs;
        
        emit ChangeAutomatedMarketMakerPairs(_automatedMarketMakerPairs, _isAutomatedMarketMakerPairs);
    }
    
    function changeMinimumBalanceBB(uint256 _newMinimumBalanceBB) public onlyDev nonReentrant {
        require(_newMinimumBalanceBB > 1 * 10**18, "Cannot set the minimumBalanceBB to lower than 1 BRNx");

        uint256 oldMinimumBalanceBB = minimumBalanceBB;
        minimumBalanceBB = _newMinimumBalanceBB;

        emit ChangeMinimumBalanceBB(_newMinimumBalanceBB, oldMinimumBalanceBB);
    }

    function changeCooldownPeriodBB(uint40 _newCooldownPeriodBB) public onlyDev nonReentrant {
        require(
            _newCooldownPeriodBB >= 1 minutes && _newCooldownPeriodBB <= 24 hours,
            "cooldownPeriodBB must be between 1 minute and 24 hours"
        );

        uint40 oldCooldownPeriodBB = cooldownPeriodBB;
        cooldownPeriodBB = _newCooldownPeriodBB;

        emit ChangeCooldownPeriodBB(_newCooldownPeriodBB, oldCooldownPeriodBB);
    }


    // DEVWALLET CHANGE -> will be subject to a timelock as a measure of security
    function initiateDevWalletChange(address _newDevWallet) public onlyDev nonReentrant {
        require(_newDevWallet != address(0), "New Dev Wallet must be a valid address");
        require(!pendingDevWalletChange.pending, "Dev Wallet change already pending");
        
        pendingDevWalletChange = DevWalletChange({
            newDevWallet: _newDevWallet,
            effectiveTime: block.timestamp + DEV_WALLET_TIMELOCK,
            pending: true
        });
    }

    function executeDevWalletChange() public onlyDev nonReentrant {
        require(pendingDevWalletChange.pending, "No Dev Wallet change pending");
        require(block.timestamp >= pendingDevWalletChange.effectiveTime, "Timelock not expired");
        
        address oldDevWallet = devWallet;
        devWallet = pendingDevWalletChange.newDevWallet;
        
        // Reset the pending change
        pendingDevWalletChange.pending = false;
        
        emit ChangeDevWallet(pendingDevWalletChange.newDevWallet, oldDevWallet);
    }

    function cancelDevWalletChange() public onlyDev nonReentrant {
        require(pendingDevWalletChange.pending, "No Dev Wallet change pending");
        
        pendingDevWalletChange.pending = false;
    }


    // TREASURYWALLET CHANGE -> will be subject to a timelock as a measure of security
    function initiateTreasuryWalletChange(address _newTreasuryWallet) public onlyDev nonReentrant {
        require(_newTreasuryWallet != address(0), "New Treasury Wallet must be a valid address");
        require(!pendingTreasuryWalletChange.pending, "Treasury Wallet change already pending");
        
        pendingTreasuryWalletChange = TreasuryWalletChange({
            newTreasuryWallet: _newTreasuryWallet,
            effectiveTime: block.timestamp + TREASURY_WALLET_TIMELOCK,
            pending: true
        });
    }

    function executeTreasuryWalletChange() public onlyDev nonReentrant {
        require(pendingTreasuryWalletChange.pending, "No Treasury Wallet change pending");
        require(block.timestamp >= pendingTreasuryWalletChange.effectiveTime, "Timelock not expired");
        
        address oldTreasuryWallet = treasuryWallet;
        treasuryWallet = pendingTreasuryWalletChange.newTreasuryWallet;
        
        // Reset the pending change
        pendingTreasuryWalletChange.pending = false;
        
        emit ChangeTreasuryWallet(pendingTreasuryWalletChange.newTreasuryWallet, oldTreasuryWallet);
    }

    function cancelTreasuryWalletChange() public onlyDev nonReentrant {
        require(pendingTreasuryWalletChange.pending, "No Treasury Wallet change pending");
        
        pendingTreasuryWalletChange.pending = false;
    }


    // PRIVATE FUNCTIONS
    function _tokenTransfer(address from, address to, uint256 amount) private {

        if (
            amount == 0 ||
            isExcludedFromFees[from] ||
            isExcludedFromFees[to] ||
            (_isEOA(from) && _isEOA(to)) ||
            swapping
            ) {
            _transfer(from, to, amount);
            return;
        }
            
        //when buy, charge tax
        if (automatedMarketMakerPairs[from]) {
            
            //apply an anti-snipe limit
            if (limitsInEffect) {
                require(amount + balanceOf(to) <= maxW, "Max wallet exceeded");
            }

            // calculate the fees and send them to this address
            uint256 fees = amount * BUY_FEES / 10000;
            amount -= fees;
            _transfer(from, address(this), fees);
        }
        
        //when sell, do nothing and continue as normal
        else if (automatedMarketMakerPairs[to]) {}

        //can't be done
        else {
            revert("Can't buy, sell or add LP on another pool");
        }

        //in the end, it'll make the swap of the tokens as requested
        _transfer(from, to, amount);
    }

    function _swapTokensForTokens(uint256 tokenAmount) private {
        // generate the algebra pair path of token -> TOKEN_PAIR_ADDRESS
        address tokenIn = address(this);
        address tokenOut = address(TOKEN_PAIR_ADDRESS);

        _approve(address(this), address(SWAP_ROUTER), tokenAmount);

        // build the params to swap
        IV3SwapRouter.ExactInputSingleParams memory params = IV3SwapRouter.ExactInputSingleParams({
            tokenIn: tokenIn,
            tokenOut: tokenOut,
            recipient: address(this),
            amountIn: tokenAmount,
            amountOutMinimum: 0,
            limitSqrtPrice: 0
        });

        // make the swap
        SWAP_ROUTER.exactInputSingle(params);
    }

    function _buyAndBurn(address caller) private {
        // make sure there's something to swap and that it follows the rules
        uint256 contractBalance = balanceOf(address(this));
        require(contractBalance >= minimumBalanceBB, "Can only call the buyAndBurn function when BRNx balance of the contract is over the minimumBalanceBB");
        require(
            block.timestamp >= lastBBCalledTime[caller] + cooldownPeriodBB,
            "Can only call the buyAndBurn function after the cooldownPeriodBB is over"
        );

        // update last called time
        lastBBCalledTime[caller] = block.timestamp;

        // swap the tokens to the TOKEN_PAIR_ADDRESS
        swapping = true;
        _swapTokensForTokens(contractBalance);
        swapping = false;

        // calculate amounts
        IERC20 token = IERC20(TOKEN_PAIR_ADDRESS);
        uint256 tokenContractBalance = token.balanceOf(address(this));
        uint256 amountToBurn = tokenContractBalance * BURN_SHARE / BUY_FEES;
        uint256 amountToTreasury = tokenContractBalance * TREASURY_SHARE / BUY_FEES;
        uint256 amountToCaller = tokenContractBalance - amountToBurn - amountToTreasury; //remaining balance goes to the caller

        // distribute amounts
        token.transfer(DEAD_ADDRESS, amountToBurn); //burn
        token.transfer(treasuryWallet, amountToTreasury); //treasury
        token.transfer(caller, amountToCaller); //caller

        emit BuyAndBurn(caller, amountToBurn, amountToTreasury, amountToCaller);
    }

    function _isEOA(address contractAddress) private view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(contractAddress)
        }
        return size == 0;
    }


    // PUBLIC FUNCTIONS
    function transfer(address to, uint256 value) public virtual override returns (bool) {
        address owner = _msgSender();
        _tokenTransfer(owner, to, value);
        return true;
    }

    function transferFrom(address from, address to, uint256 value) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _tokenTransfer(from, to, value);
        return true;
    }


    // COMMUNITY FUNCTIONS
    function buyAndBurn() external {
        require(!limitsInEffect, "Can't call buyAndBurn while limits are in effect");
        _buyAndBurn(msg.sender);
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):