Hey guys! I'm currently working on an ERC20 token that implements a buy/sell tax on every Sushiswap buy/sell. I override the _transfer
function below to detect if the sender/recipient is the Sushiswap pair. I take the taxed amount (2% of the transfer amount) and swap half of it for WETH, and then pair the WETH with the other half of the taxed amount to deposit into the liquidity pool. I am having a strange issue however: the tax functionality works fine when I'm doing a simple transfer to the sushiswapPair
and the liquidity gets deposited successfully. However, when I try to perform a swap within the Sushi app, the frontend is unable to estimate the gas required (indicating that the transaction will fail). I get the same issue when directly calling the swapExactETHForTokens
function within the Sushi router contract.
I initially presumed the issue to be related to intermediate calls from Sushi contracts, for which taxes would be taken. I prevented this by maintaining a variable isSwapping
to detect if the contract is in the middle of a swap and thus should avoid taxing the transfer amounts. I do not see any other potential points of failure but still am running into issues. I would really appreciate if someone could help me spot the issue and point me in the right direction! Below is portion of my code (the rest of the code is just standard ERC20 implementation, omitted for brevity):
function _transfer(address sender, address recipient, uint256 amount) internal override {
if (isSwapping || amount == 0) {
super._transfer(sender, recipient, amount);
return;
}
uint256 remainingAmount = amount;
uint256 taxAmount;
if (recipient == sushiswapPair && sender != address(this)) {
// Buy tax
taxAmount = amount * buyTaxRate / 100;
} else if (sender == sushiswapPair && recipient != address(this)) {
// Sell tax
taxAmount = amount * sellTaxRate / 100;
}
remainingAmount -= taxAmount;
if (taxAmount > 0) {
isSwapping = true;
// Swap half for ETH
uint256 halfTaxAmount = taxAmount / 2;
uint256 otherHalfTaxAmount = taxAmount - halfTaxAmount;
_swapTokensForETH(halfTaxAmount);
isSwapping = false;
// Add liquidity to the pool
uint256 ethBalance = address(this).balance;
super._transfer(sender, address(this), otherHalfTaxAmount);
_addLiquidity(otherHalfTaxAmount, ethBalance);
}
super._transfer(sender, recipient, remainingAmount);
}
function _swapTokensForETH(uint256 tokenAmount) internal {
// Generate the sushi pair path of token -> WETH
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = sushiswapRouter.WETH();
_approve(address(this), address(sushiswapRouter), tokenAmount);
// Make the swap
sushiswapRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0, // Accept any amount of ETH
path,
address(this),
block.timestamp
);
}
function _addLiquidity(uint256 tokenAmount, uint256 ethAmount) internal {
// Approve token transfer to cover all possible scenarios
_approve(address(this), address(sushiswapRouter), tokenAmount);
// Add the liquidity
(, uint256 amountToken, uint256 amountETH) = sushiswapRouter.addLiquidityETH{value: ethAmount}(
address(this),
tokenAmount,
0, // Slippage is unavoidable
0, // Slippage is unavoidable
owner(),
block.timestamp
);
emit LiquidityAdded(amountToken, amountETH);
}
Cheers!