Created
September 27, 2024 07:13
-
-
Save AndreiD/b36e07bf7323bfe7f91bd4e96d2f9ff6 to your computer and use it in GitHub Desktop.
token_with_buy_sell_tax.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.8.23; | |
abstract contract Ownable { | |
address private _owner; | |
constructor() { | |
_owner = msg.sender; | |
} | |
function owner() public view virtual returns (address) { | |
return _owner; | |
} | |
modifier onlyOwner() { | |
require(owner() == msg.sender, "Ownable: caller is not the owner"); | |
_; | |
} | |
function renounceOwnership() public virtual onlyOwner { | |
_owner = address(0); | |
} | |
function _transferOwnership(address newOwner) public virtual onlyOwner { | |
_owner = newOwner; | |
} | |
} | |
interface IERC20 { | |
function balanceOf(address account) external view returns (uint256); | |
function transfer(address recipient, uint256 amount) external; | |
} | |
interface IUniswapV2Factory { | |
function createPair(address tokenA, address tokenB) | |
external | |
returns (address pair); | |
} | |
interface IUniswapRouter { | |
function factory() external pure returns (address); | |
function WETH() external pure returns (address); // Attention: on some l2 like pulex this is changed to WPLS! check it | |
function swapExactTokensForETHSupportingFeeOnTransferTokens( | |
uint256 amountIn, | |
uint256 amountOutMin, | |
address[] calldata path, | |
address to, | |
uint256 deadline | |
) external; | |
} | |
contract Dog is Ownable { | |
//variables------------- | |
string private constant _name = "Dog3"; // CHANGE ME! | |
string private constant _symbol = "Dog3"; // CHANGE ME! | |
uint256 private constant _totalSupply = 1_000_000_000 * 1e18; | |
uint256 public buyFee = 10; // 1.0% // CHANGE ME! | |
uint256 public sellFee = 20; // 2.0% // CHANGE ME! | |
//variables------------- | |
uint256 public swapTokensAtAmount = 100 * 1e18; // CHANGE ME! (also changable from swapTokensAtAmount function) | |
address private treasuryWallet = 0x123...; //CHANGE ME! | |
bool private swapping; | |
mapping(address => uint256) private _balances; | |
mapping(address => mapping(address => uint256)) private _allowances; | |
mapping(address => bool) private _isExcludedFromFees; | |
mapping(address => bool) private _isExcludedMaxTransactionAmount; | |
mapping(address => bool) private liqudityPools; | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
event Approval( | |
address indexed owner, | |
address indexed spender, | |
uint256 value | |
); | |
//0xD99D1c33F9fC3444f8101754aBC46c52416550D1 - BSC Pancake Testnet Router | |
IUniswapRouter public constant uniswapRouter = | |
IUniswapRouter(0xD99D1c33F9fC3444f8101754aBC46c52416550D1); // CHANGE ME! | |
address public uniswapPair; | |
constructor() { | |
uniswapPair = IUniswapV2Factory(uniswapRouter.factory()).createPair( | |
address(this), | |
uniswapRouter.WETH() | |
); | |
liqudityPools[uniswapPair] = true; | |
setExcludedFromFees(owner(), true); | |
setExcludedFromFees(address(this), true); | |
setExcludedFromFees(address(0xdead), true); | |
setExcludedFromFees(treasuryWallet, true); | |
_balances[owner()] = _totalSupply; | |
emit Transfer(address(0), owner(), _totalSupply); | |
_approve(address(this), address(uniswapRouter), type(uint256).max); | |
} | |
receive() external payable {} | |
function name() public pure returns (string memory) { | |
return _name; | |
} | |
function symbol() public pure returns (string memory) { | |
return _symbol; | |
} | |
function decimals() public pure returns (uint8) { | |
return 18; | |
} | |
function totalSupply() public pure returns (uint256) { | |
return _totalSupply; | |
} | |
function balanceOf(address account) public view returns (uint256) { | |
return _balances[account]; | |
} | |
function allowance(address owner, address spender) | |
public | |
view | |
returns (uint256) | |
{ | |
return _allowances[owner][spender]; | |
} | |
function approve(address spender, uint256 amount) external returns (bool) { | |
_approve(msg.sender, spender, amount); | |
return true; | |
} | |
function _approve( | |
address owner, | |
address spender, | |
uint256 amount | |
) private { | |
require(owner != address(0), "ERC20: approve from the zero address"); | |
require(spender != address(0), "ERC20: approve to the zero address"); | |
_allowances[owner][spender] = amount; | |
emit Approval(owner, spender, amount); | |
} | |
function transfer(address recipient, uint256 amount) | |
external | |
returns (bool) | |
{ | |
_transfer(msg.sender, recipient, amount); | |
return true; | |
} | |
function transferFrom( | |
address sender, | |
address recipient, | |
uint256 amount | |
) external returns (bool) { | |
uint256 currentAllowance = _allowances[sender][msg.sender]; | |
if (currentAllowance != type(uint256).max) { | |
require( | |
currentAllowance >= amount, | |
"ERC20: transfer amount exceeds allowance" | |
); | |
unchecked { | |
_approve(sender, msg.sender, currentAllowance - amount); | |
} | |
} | |
_transfer(sender, recipient, amount); | |
return true; | |
} | |
function _transfer( | |
address from, | |
address to, | |
uint256 amount | |
) private { | |
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 contractTokenBalance = balanceOf(address(this)); | |
bool overMinTokenBalance = contractTokenBalance >= swapTokensAtAmount; | |
if ( | |
overMinTokenBalance && | |
!swapping && | |
!liqudityPools[from] && | |
!_isExcludedFromFees[from] && | |
!_isExcludedFromFees[to] | |
) { | |
swapping = true; | |
swapTokensForEth(contractTokenBalance); | |
(bool success, ) = address(treasuryWallet).call{ | |
value: address(this).balance | |
}(""); | |
require(success, "withdrawal failed"); | |
swapping = false; | |
} | |
//take the fees in token | |
bool takeFee = !swapping && (liqudityPools[from] || liqudityPools[to]); | |
if (_isExcludedFromFees[from] || _isExcludedFromFees[to]) { | |
takeFee = false; | |
} | |
uint256 senderBalance = _balances[from]; | |
require( | |
senderBalance >= amount, | |
"ERC20: transfer amount exceeds balance" | |
); | |
uint256 fees = 0; | |
if (takeFee) { | |
if (liqudityPools[from]) { | |
// this is a buy | |
fees = (amount * buyFee) / 1000; | |
} else if (liqudityPools[to]) { | |
// this is a sell | |
fees = (amount * sellFee) / 1000; | |
} | |
if (fees > 0) { | |
amount = amount - fees; | |
_balances[from] -= fees; | |
_balances[address(this)] += fees; | |
emit Transfer(from, address(this), fees); | |
} | |
} | |
_balances[from] -= amount; | |
_balances[to] += amount; | |
emit Transfer(from, to, amount); | |
} | |
function setExcludedFromFees(address account, bool isExcluded) | |
public | |
onlyOwner | |
{ | |
_isExcludedFromFees[account] = isExcluded; | |
} | |
function setSwapAtAmount(uint256 newSwapAmount) external onlyOwner { | |
swapTokensAtAmount = newSwapAmount; | |
} | |
function setLiquidityPoolAddress(address pair, bool isLP) external onlyOwner { | |
liqudityPools[pair] = isLP; | |
} | |
//changes the treasury wallet | |
function changeTreasuryWallet(address newwallet) external onlyOwner { | |
treasuryWallet = newwallet; | |
} | |
// Function to set buy and sell fees | |
function setFees(uint256 newBuyFee, uint256 newSellFee) external onlyOwner { | |
require(newBuyFee + newSellFee <= 100, "Total fee cannot exceed 10%"); | |
buyFee = newBuyFee; | |
sellFee = newSellFee; | |
} | |
//if people send erc20 tokens by mistake to the contract, the owner can withdraw them | |
function withdrawStuckToken(address token, address to) external onlyOwner { | |
uint256 _contractBalance = IERC20(token).balanceOf(address(this)); | |
IERC20(token).transfer(to, _contractBalance); | |
} | |
function swapTokensForEth(uint256 tokenAmount) private { | |
// generate the uniswap pair path of token -> weth | |
address[] memory path = new address[](2); | |
path[0] = address(this); | |
path[1] = uniswapRouter.WETH(); | |
// no need to call approve here, since it's called in the constructor for max value | |
//_approve(address(this), address(uniswapRouter), tokenAmount); | |
// make the swap | |
uniswapRouter.swapExactTokensForETHSupportingFeeOnTransferTokens( | |
tokenAmount, | |
0, // accept any amount of ETH | |
path, | |
address(this), | |
block.timestamp | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment