Untitled
unknown
plain_text
a year ago
8.5 kB
2
Indexable
Never
//SPDX-License-Identifier: MIT pragma solidity 0.8.19; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; /// @title PUK: An erc20 token with sell fees contract PUK is ERC20, Ownable { ///ERRORS // error MaxFeeLimitExceeded(); error ZeroAddressNotAllowed(); error UpdateBoolValue(); error AmountNotInRange(); error CanNotModifyMainPair(); error NotAuthorized(); /// @notice Max fees Limit uint16 constant private MAX_FEE = 6; /// @notice Minimum tax tokens limit required to swap for BNB uint256 constant private MIN_SWAP_AT_AMOUNT = 1e3 * 1e18; /// @notice max limit to swap collected tax for bnb per tx uint256 constant private MAX_SWAP_AT_AMOUNT = 5e9 * 1e18; /// @notice global burn address address constant private DEAD = address(0xdead); /// @notice fees on every sell uint16 public sellFees = 6; /// @notice fees wallet to receive bnb address public feeWallet = address(0x123); /// @notice pancakswap main pair address (TOKEN/BNB) address public uniswapV2Pair; /// @notice router address for pancakeswap IUniswapV2Router02 public uniswapV2Router; /// @notice max Supply for token uint256 maxSupply = 5e11 * 1e18; // 500 Billion /// @notice collected tax token amount after that it will be swapped for bnb uint256 swapTokensAtAmount = (maxSupply * 10) / 100000; // 0.01% of the supply /// @notice mapping for users excluded from fees mapping(address => bool) public isExcludedFromFees; /// @notice mapping for liquidity pairs addresses mapping(address=> bool) public isLiquidityPair; /// @notice allows collected tokens fees to swapped for bnb bool public swapEnabled = true; bool swapping; ///events event SwapTokensAmountUpdated (uint256 indexed newAmount); event FeeWalletUpdated(address indexed newFeeWallet); event ExcludedFromFees (address indexed account, bool value); event NewLPUpdated(address indexed lp, bool value); event FeesUpdated( uint16 indexed sellFee); /// @dev create an erc20 token using openzeppelin ownable and erc20. /// sets the pancakeswap router address, create main pair, exclude the /// owner, feewallet, burn address and token itself from fees. mint the /// maxSupply to the owner during deployment. constructor() ERC20("Punk Rabbit", "PUK"){ IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02( 0x10ED43C718714eb63d5aA57B78B54704E256024E//Pancakeswap V2 Router ); uniswapV2Router = _uniswapV2Router; uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory()) .createPair(address(this), _uniswapV2Router.WETH()); isLiquidityPair[uniswapV2Pair] = true; isExcludedFromFees[msg.sender] = true; isExcludedFromFees[address(this)] = true; isExcludedFromFees[feeWallet] = true; isExcludedFromFees[DEAD] = true; _mint(owner(), maxSupply); } ///@dev update fees wallet to receive BNB ///@param _newFeeWallet: new wallet address for fees ///Requirements - /// _newFeeWallet address should not be zero address. function updateFeesWallet (address _newFeeWallet) external onlyOwner { if(_newFeeWallet == address(0)){ revert ZeroAddressNotAllowed(); } feeWallet = _newFeeWallet; emit FeeWalletUpdated(_newFeeWallet); } ///@dev update fees for sell ///@param sell: new sell fees ///Requirements- /// sell should be less than equal to MAX_FEE function updateFees (uint16 sell) external onlyOwner { if(sell > MAX_FEE){ revert MaxFeeLimitExceeded(); } sellFees = sell; emit FeesUpdated( sell); } ///@dev exclude or include in fee mapping ///@param user: user to exclude or include in fee function excludeFromFees (address user, bool isExcluded) external onlyOwner { if(isExcludedFromFees[user] == isExcluded){ revert UpdateBoolValue(); } isExcludedFromFees[user] = isExcluded; emit ExcludedFromFees(user, isExcluded); } ///@dev add or remove new pairs ///@param newPair; new pair address ///@param value: boolean value true true for adding, false for removing ///Requirements - ///Can't modify uniswapV2Pair (main pair) function setLiquidityPairs (address newPair, bool value) external onlyOwner{ if(newPair == uniswapV2Pair){ revert CanNotModifyMainPair(); } isLiquidityPair[newPair] = value; emit NewLPUpdated(newPair, value); } ///@dev update the swap token amount ///@param _newSwapAmount: new token amount to swap threshold ///Requirements-- /// amount must greator than equal to MIN_SWAP_AT_AMOUNT function setSwapTokensAtAmount (uint256 _newSwapAmount) external onlyOwner { if(_newSwapAmount < MIN_SWAP_AT_AMOUNT && _newSwapAmount > MAX_SWAP_AT_AMOUNT){ revert AmountNotInRange(); } swapTokensAtAmount = _newSwapAmount; emit SwapTokensAmountUpdated(_newSwapAmount); } ///@notice dev can claim stucked tokens, if sent by someone accidently ///@param token: address to token to be resuced function claimStuckedTokens (address token) external { if(msg.sender != feeWallet){ revert NotAuthorized(); } IERC20 tkn = IERC20(token); uint256 balance = tkn.balanceOf(address(this)); tkn.transfer(feeWallet, balance); } ///@notice transfer function to manage token transfer/fees/limits function _transfer( address from, address to, uint256 amount ) internal override { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); require(amount > 0, "Transfer amount must be greater than zero"); uint256 contractBalance = balanceOf(address(this)); if ( swapEnabled && !swapping && !isLiquidityPair[from] && !isExcludedFromFees[from] && !isExcludedFromFees[to] && contractBalance >=swapTokensAtAmount ) { if(contractBalance > MAX_SWAP_AT_AMOUNT){ contractBalance = MAX_SWAP_AT_AMOUNT; } swapping = true; swapTokensForEth(contractBalance); swapping = false; } bool takeFee = !swapping; // if any account belongs to _isExcludedFromFee account then remove the fee if (isExcludedFromFees[from] || isExcludedFromFees[to]) { takeFee = false; } uint256 fees = 0; // only take fees on buys/sells, do not take on wallet transfers if (takeFee) { //on sell if ( isLiquidityPair[to] && sellFees > 0) { fees = (amount * sellFees) / 100; } if (fees > 0) { super._transfer(from, address(this), fees); } amount -= fees; } super._transfer(from, to, amount); } ///@notice private function to swap tax to BNB function swapTokensForEth(uint256 tokenAmount) private { // generate the uniswap pair path of token -> wbnb address[] memory path = new address[](2); path[0] = address(this); path[1] = uniswapV2Router.WETH(); if(allowance(address(this), address(uniswapV2Router)) < tokenAmount){ _approve(address(this), address(uniswapV2Router), type(uint256).max); } // make the swap uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens( tokenAmount, 0, // accept any amount of BNB path, feeWallet, block.timestamp ); } }