v2-periphery
v2-periphery copied to clipboard
Can't call UniswapRouterV2.swapExactTokensForTokens from another contract
I'm trying to integrate Uniswap into my own contract, I have given the UniswapRouterV2 contract allowance to transfer tokens on my behalf but still I'm getting TRANSFER_FROM_FAILED. I have been testing in Ropsten. The weird stuff is that calling the router contract directly (from Etherscan for example) with the exact same parameters does not fail at all and correctly swaps the token and deposits the target token in the target account.
I'm posting here my contract code, is a really simple Test contract.
pragma solidity ^0.8.1;
pragma experimental ABIEncoderV2;
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
contract PaymentGateway {
address internal constant UNISWAP_ROUTER_ADDRESS = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address internal constant UNISWAP_FACTORY_ADDRESS = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
IUniswapV2Router02 public uniswapRouter;
IUniswapV2Factory public uniswapFactory;
constructor() {
uniswapRouter = IUniswapV2Router02(UNISWAP_ROUTER_ADDRESS);
uniswapFactory = IUniswapV2Factory(UNISWAP_FACTORY_ADDRESS);
}
function swapTokensForExactTokens(
uint _amount,
uint _min,
address _sourceToken,
address _targetToken,
address _recipient,
uint _deadline
) external returns (uint[] memory) {
address[] memory path = new address[](2);
path[0] = _sourceToken;
path[1] = _targetToken;
uint[] memory amounts = uniswapRouter.swapTokensForExactTokens(
_amount,
_min,
path,
_recipient,
_deadline
);
return amounts;
}
function swapExactTokensForTokens(
uint _amount,
uint _min,
address _sourceToken,
address _targetToken,
address _recipient,
uint _deadline
) external returns (uint[] memory) {
address[] memory path = new address[](2);
path[0] = _sourceToken;
path[1] = _targetToken;
uint[] memory amounts = uniswapRouter.swapExactTokensForTokens(
_amount,
_min,
path,
_recipient,
_deadline
);
return amounts;
}
}
Has anyone experienced something similar?
Thanks in advance
Same issue and trying to get help for weeks, the support and documentation is very poor. Here is my relevant code:
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual override lock(_isTransferLocked) notNull(amount) {
require(
_balances[sender] >= amount,
"ERC20: transfer amount exceeds balance"
);
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 (!_isExcludedFromFees[sender] && !_isExcludedFromFees[recipient]) {
uint256 updatedAmount = _beforeTokenTransfer(sender, amount);
amount = updatedAmount;
}
_balances[sender] -= amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
function _beforeTokenTransfer(address sender, uint256 amount)
internal
returns (uint256)
{
uint256 updatedAmount = amount;
if (_liquidityTax != 0) {
uint256 liquidityFee = (amount * _liquidityTax) / 100;
_balances[sender] -= liquidityFee;
_balances[address(this)] += liquidityFee;
emit Transfer(sender, address(this), liquidityFee);
if (
_balances[address(this)] >= _minTokensRequiredBeforeSwap &&
_isAutoSwapAndLiquify
// && sender != _uniswapV2Pair // not sure why this is needed... 🤔
) {
_swap(_balances[address(this)] / 2);
// uint256 ethReceived = _swap(_balances[address(this)] / 2);
// (uint256 amountETH, uint256 amountToken) =
// _liquify(halfContractBalance, ethReceived);
// _totalLiquidityETH += amountETH;
// _totalLiquidity += amountToken;
}
updatedAmount -= liquidityFee;
}
return updatedAmount;
}
/*
* (Uni|Pancake)Swap functions
*/
// Required to recieve ETH from uniswapV2Router on swaps
receive() external payable {}
function _swap(uint256 amountIn) internal returns (uint256) {
// contract's current BNB/ETH balance
uint256 initialBalance = address(this).balance;
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = _uniswapV2Router.WETH();
_approve(address(this), address(_uniswapV2Router), type(uint256).max);
// 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
);
return address(this).balance - initialBalance;
}
When commenting:
_swap(_balances[address(this)] / 2);
Everything works, when not commenting this happens:
Could anyone from the UniSwap team take time to look at this and add documentation to their website because so far as I said it is pretty poor!
@santiac89 @aress31 did either of you find a way to resolve this issue? I'm trying to call swapExactTokensForTokens from a contract, and I'm getting the same error 'TransferHelper: TRANSFER_FROM_FAILED'.