I am trying to implement a simple swap (my ERC20 token against ETH) and noticed a strange bug. The _approve
function does not seem to work properly and is causing Uniswap to reject any buy/sell attempt.
Here is the relevant code:
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
uint256 totalSupply_,
address router_,
uint8 liquidityTax_
) ERC20(name_, symbol_) {
_decimals = decimals_;
_liquidityTax = liquidityTax_;
_minTokensRequiredBeforeSwap = 1 * 10**_decimals; // To change on prod
// _minTokensRequiredBeforeSwap = 10**6 * 10**_decimals;
_uniswapV2Router = IUniswapV2Router02(router_);
address pair =
IUniswapV2Factory(_uniswapV2Router.factory()).getPair(
_uniswapV2Router.WETH(),
address(this)
);
// Pair not yet created
if (pair == address(0)) {
_uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(_uniswapV2Router.WETH(), address(this));
} else {
_uniswapV2Pair = pair;
}
setIsExcludedFromPayingFees(address(this), true);
setIsExcludedFromPayingFees(owner(), true);
_mint(owner(), totalSupply_ * (10**decimals_));
}
function _transfer(
address sender,
address recipient,
uint256 amount
) internal override notNull(amount) {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(
sender != recipient,
"_transfer: 'sender' cannot also be 'recipient'"
);
if (!_isExcludedFromPayingFees[sender]) {
amount = _beforeTokenTransfer(sender, amount);
}
uint256 senderBalance = _balances[sender];
require(
senderBalance >= amount,
"ERC20: transfer amount exceeds balance"
);
_balances[sender] = senderBalance - amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
// Track: https://forum.openzeppelin.com/t/updating-balance-on-inherited-contracts/8133
function _beforeTokenTransfer(address sender, uint256 amount)
internal
returns (uint256)
{
uint256 updatedAmount = amount;
if (_liquidityTax != 0) {
uint256 liquidityFee = (amount * _liquidityTax) / (10**2);
_balances[sender] -= liquidityFee;
_balances[address(this)] += liquidityFee;
bool overMinTokensRequiredBeforeSwap =
_balances[address(this)] >= _minTokensRequiredBeforeSwap;
if (
overMinTokensRequiredBeforeSwap &&
!_inSwapAndLiquify &&
_isAutoSwapAndLiquify
// && sender != _uniswapV2Pair // not sure why this is needed... 🤔
) {
uint256 halfContractBalance = _balances[address(this)] / 2;
uint256 ethReceived = _swap(halfContractBalance);
// (uint256 amountETH, uint256 amountToken) =
// _liquify(halfContractBalance, ethReceived);
// _totalLiquidityETH += amountETH;
// _totalLiquidity += amountToken;
}
updatedAmount -= liquidityFee;
}
return updatedAmount;
}
// Required to recieve ETH from uniswapV2Router on swaps
receive() external payable {}
function _swap(uint256 amountIn) private returns (uint256) {
// contract's current BNB/ETH balance
uint256 initialBalance = address(this).balance;
// swap half of the tokens to ETH
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = _uniswapV2Router.WETH();
_approve(address(this), address(_uniswapV2Router), amountIn);
// Swap tokens for ETH/BNB
_uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
amountIn,
0, // TODO: use an Oracle
path,
address(this), // this contract will receive the ETH that were swapped from the token
block.timestamp + 60 * 1000
);
// Figure out the exact amount of tokens received from swapping
// Check: https://github.com/Uniswap/uniswap-v2-periphery/issues/92
uint256 ethReceived = address(this).balance - initialBalance;
// TODO: Check if a similar event is already emitted
emit SwapExactTokensForETHSupportingFeeOnTransferTokens(
amountIn,
ethReceived
);
return ethReceived;
}
I came to the conclusion that the error is caused by the _allowance method because when trying to troubleshot this bug I ran the following command that shows that either the code fails before the swapExactTokensForETHSupportingFeeOnTransferTokens
being called or that it is the cause of this failure (later option is most likely given the error returned by Uniswap).
truffle(ropsten)> await token.allowance(token.address,"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D").then(x => console.log(x.toString()))
0
Further information available at: https://github.com/Uniswap/uniswap-v2-core/issues/119
If someone could help with this that would be fabulous already spent 2 full days on this bug with no success at all! Starting to give up… Although this - Uniswap - is (in the paper) a very straightforward lib/function to use.