Hello OpenZeppelin Community,
I work on an ERC20 token and integrate into it my own functionality for transaction fees. I have a specific question regarding the implementation of liquidity fees in my _transfer function.
In my contract I charge a 2% transaction fee for marketing and another 2% for liquidity. Here is a simplified part of my code to give an idea:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
contract CustomToken is ERC20, ERC20Burnable, ReentrancyGuard, Ownable {
// Public variables for contract configuration
address public marketingWallet;
address public uniswapV2RouterAddress;
IUniswapV2Router02 public uniswapV2Router;
address public uniswapV2Pair;
// Constants and state variables
uint256 public constant TOTAL_SUPPLY = 450000000000000 * 10**18;
uint256 public minEthBeforeLiquidity = 0.05 ether;
uint256 public lastLiquidityAddTime;
// Constructor to initialize the contract with specified parameters
constructor(
address _marketingWallet,
address _uniswapV2RouterAddress,
address initialOwner
) ERC20("Testing", "GRC") {
marketingWallet = _marketingWallet;
uniswapV2RouterAddress = _uniswapV2RouterAddress;
// Initialize Uniswap V2 Router and Pair
uniswapV2Router = IUniswapV2Router02(uniswapV2RouterAddress);
uniswapV2Pair = IUniswapV2Factory(uniswapV2Router.factory()).createPair(address(this), uniswapV2Router.WETH());
// Mint the total supply to the initial owner
_mint(initialOwner, TOTAL_SUPPLY);
}
// Overridden _transfer function to implement custom transfer logic with fees
function _transfer(address from, address to, uint256 amount) internal virtual override {
// Calculate marketing and liquidity fees
uint256 marketingFee = (amount * 2) / 100;
uint256 liquidityFee = (amount * 2) / 100;
uint256 fees = marketingFee + liquidityFee;
// Calculate the amount after deducting fees
uint256 sendAmount = amount - fees;
// Perform the transfer with the deducted amount
super._transfer(from, to, sendAmount);
// Transfer marketing fee to the marketing wallet
if (marketingFee > 0) {
super._transfer(from, marketingWallet, marketingFee);
}
// Check conditions for adding liquidity and add if conditions are met
uint256 minTimeInterval = 24 hours; // Example: 24 hours
if (liquidityFee > 0 && from != uniswapV2Pair && address(this).balance >= minEthBeforeLiquidity && (block.timestamp - lastLiquidityAddTime) >= minTimeInterval) {
addLiquidity(liquidityFee, address(this).balance);
lastLiquidityAddTime = block.timestamp;
}
}
// Internal function to swap tokens for ETH
function swapTokensForEth(uint256 tokenAmount) private {
// Setup the path for token swap
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapV2Router.WETH();
// Approve token amount for the router and perform the swap
_approve(address(this), address(uniswapV2Router), tokenAmount);
uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0, // Minimum amount of ETH to accept
path,
address(this),
block.timestamp
);
}
// Internal function to add liquidity to Uniswap
function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
// Approve token amount for the router
_approve(address(this), address(uniswapV2Router), tokenAmount);
// Add liquidity to Uniswap pool
uniswapV2Router.addLiquidityETH{value: ethAmount}(
address(this),
tokenAmount,
0, // Minimum amount of tokens to add
0, // Minimum amount of ETH to add
owner(), // Recipient of the liquidity tokens
block.timestamp
I have checked the transactions on the Goerli testnet and I am not sure where these fees are stored.
Here is a link to the relevant transaction on Goerli:
(https://goerli.etherscan.io/tx/0xe7c56de792f4fd88c6e53d47c98ad7e8e79cb82ab6f1002d632c88fde2fd4efe)
I would be very grateful for any suggestions, examples or advice on how to efficiently and securely process these types of fees within a smart contract.
Thank you in advance for your help and advice!