i have a problem with swapExactETHForTokens(). It seems to fail everytime I change the input value to something else than Zero.
To help you to follow the path of de DATA, I show you :
swapExactETHForTokens() from the pancakeswap contract
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external virtual override payable ensure(deadline) returns (uint[] memory amounts) { require(path[0] == WETH, 'PancakeRouter: INVALID_PATH'); amounts = PancakeLibrary.getAmountsOut(factory, msg.value, path); require(amounts[amounts.length - 1] >= amountOutMin, 'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT'); IWETH(WETH).deposit{value: amounts[0]}(); assert(IWETH(WETH).transfer(PancakeLibrary.pairFor(factory, path[0], path[1]), amounts[0])); _swap(amounts, path, to);
getAmountsOut() from the same contract. That is used inside the first one.
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { require(path.length >= 2, 'PancakeLibrary: INVALID_PATH'); amounts = new uint[](path.length); amounts[0] = amountIn; for (uint i; i < path.length - 1; i++) { (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); }
and getAmoutOut() called from the end of getAmountsOut():
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { require(amountIn > 0, 'PancakeLibrary: INSUFFICIENT_INPUT_AMOUNT'); require(reserveIn > 0 && reserveOut > 0, 'PancakeLibrary: INSUFFICIENT_LIQUIDITY'); uint amountInWithFee = amountIn.mul(9975); uint numerator = amountInWithFee.mul(reserveOut); uint denominator = reserveIn.mul(10000).add(amountInWithFee); amountOut = numerator / denominator;
My problem and the progression, with different configurations :
1. With {value:msg.value}, {value:0} or no value.
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens(0,path,address(this),deadline)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:msg.value}(0,path,address(this),deadline)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:0}(0,path,address(this),deadline)
- In all of these cases, I get the error message 'INSUFFICIENT_INPUT_AMOUNT'.
This message comes from getAmoutOut(), called by getAmountsOut(), called by swapExactETHForTokens(), because my input amount is not > 0. So the data seems to be well recognized.
2. With non zero value ex:{value:1000000000000000000}
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:1000000000000000000}(0,path,address(this),deadline)
- I get the error 'Error: Transaction reverted: function call failed to execute'. So it shows that the function stops somewhere.
To go forward, I have changed the path[0] = WBNB_contract to path[0] = Cake_contract. So it should display the error :'PancakeRouter: INVALID_PATH'.
3. With Non zero value, with path[0]=CAKE (instead of WBNB)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:1000000000000000000}(0,path,address(this),deadline)
- Gives me again 'Error: Transaction reverted: function call failed to execute' for both of them. So the data doesn't seem to go inside the function.
4. With no value and path[0]=CAKE (instead of WBNB)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens(0,path,address(this),deadline)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:0}(0,path,address(this),deadline)
IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:msg.value}(0,path,address(this),deadline)
- But without a value, i get the error 'PancakeRouter: INVALID_PATH'. So the error is from the first line of the function swapExactETHForTokens().
It appears that with a non zero value, the data doesn't penetrate inside the function. i am using hardhat, and am on pragma 0.6.6. Am I doing something wrong? I have lost all my hairs after two days of research.
this is my function, called from pancakeCall():
function placeTrade(address _fromToken,address _toToken,uint256 _amountIn) payable public returns (uint256) {
address pair = IUniswapV2Factory(PANCAKE_FACTORY).getPair(_fromToken,_toToken);
require(pair != address(0), "Pool does not exist (for trade)");
// Calculate Amount Out
address[] memory path = new address[](2);
path[0] = _fromToken;
path[1] = _toToken;
uint256 amountRequired = IUniswapV2Router02(PANCAKE_ROUTER).getAmountsOut(_amountIn, path)[1];
// Perform Arbitrage - Swap for another token
uint256 amountReceived ;
console.log('- fromToken:',path[0], "toToken:",path[1]);
if (_fromToken == WBNB) {
console.log('- BNB / token');
TransferHelper.safeApprove(_fromToken, address(PANCAKE_ROUTER),_amountIn);
amountReceived = IUniswapV2Router02(PANCAKE_ROUTER).swapExactETHForTokens{value:msg.value}(0,path,address(this),deadline)[1];
The startTrade() function is called from the pancakeswap call, right after i asked for a flashswap with the swap() function from pancakeswap. This is my pancakeCall()function
function pancakeCall(address _sender,uint256 _amount0,uint256 _amount1,bytes calldata _data) external {
address token0 = IUniswapV2Pair(msg.sender).token0();
address token1 = IUniswapV2Pair(msg.sender).token1();
address pair = IUniswapV2Factory(PANCAKE_FACTORY).getPair(token0,token1);
require(msg.sender == pair, "The sender needs to match the pair");
require(_sender == address(this), "Sender should match this contract");
(address starterToken, address tokenLink1, address tokenLink2, uint256 amount, address myAddress) = abi.decode(_data,(address, address, address, uint256, address));
uint256 fee = ((amount * 3) / 997) + 1;
uint256 amountToRepay = amount + fee;
uint256 loanAmount = _amount0 > 0 ? _amount0 : _amount1;
uint256 trade1AcquiredCoin = placeTrade(starterToken, tokenLink1, loanAmount);//with starterToken =WBNB