0

first off I’d like to say that I’m a noob in Solidity so this issue might sound so trivial, pls bear with me. I’m running into a compiler error on line 61 (Stack too deep). I suppose an easy fix would be to break blocks #2 and #3 into smaller functions but still be able to return the results on #4 for the parent function (#1). Basically, I’m would like to call the ‘buy’ function and then return #4 while breaking blocks #2 and #3 into smaller functions as a workaround “Stack too deep” error. How do I achieve this? Any help would be appreciated.

// Main function  (#1)
    function buy(address baseToken, address token, address exchangeRouterAddress) public payable returns (uint256, uint256, uint256, uint256, uint256, uint256) {
        uint256[] memory gas = new uint256[](2);

        IUniswapV2Router02 exchangeRouter = IUniswapV2Router02(exchangeRouterAddress);

        IERC20 _token = IERC20(token);
        IERC20 _baseToken = IERC20(baseToken);
        address[] memory path = new address[](2);

        if(baseToken != exchangeRouter.WETH()) {
            path[0] = exchangeRouter.WETH();
            path[1] = baseToken;
            exchangeRouter.swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(0, path, address(this), block.timestamp + 20);
        }
        else {
            IWETH(baseToken).deposit{value: msg.value}();
        }
        uint256 amount = _baseToken.balanceOf(address(this));
        
        // Nest function 1    (#2)
        path = new address[](2);
        path[0] = baseToken;
        path[1] = token;
        uint256 expToken = exchangeRouter.getAmountsOut(amount, path)[1];
        _baseToken.approve(exchangeRouterAddress, type(uint256).max);
        uint256 startGas = gasleft();
        exchangeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(amount, 0, path, address(this), block.timestamp + 20);
        gas[0] = startGas - gasleft();
        uint256 rcvdToken = _token.balanceOf(address(this));

        // Nest function 2    (#3)
        path = new address[](2);
        path[0] = token;
        path[1] = baseToken;
        uint256 expBaseToken = exchangeRouter.getAmountsOut(rcvdToken, path)[1];
        _token.approve(exchangeRouterAddress, type(uint256).max);
        startGas = gasleft();
        exchangeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(rcvdToken, 0, path, address(this), block.timestamp + 20);
        gas[1] = startGas - gasleft();
        uint256 rcvdBaseToken = _baseToken.balanceOf(address(this));

        // Finally return all results at once    (#4)
        return (expToken, rcvdToken, gas[0], expBaseToken, rcvdBaseToken, gas[1]);
    }

Remix screenshot

1
  • Can you add all your smart contract code? Mar 17, 2022 at 17:04

1 Answer 1

0

using some tricks from https://soliditydeveloper.com/stacktoodeep, I'm able to compile your contract without the stack too deep error.

Here is an updated version, please note I didn't try to run it.

contract ReBuy {
    struct ExchangeResult {
        uint256 expected;
        uint256 received;
        uint256 gas;
    }

    function deposit(address token, address exchangeRouterAddress) internal {
        IUniswapV2Router02 exchangeRouter = IUniswapV2Router02(
            exchangeRouterAddress
        );
        address[] memory path = new address[](2);

        if (token != exchangeRouter.WETH()) {
            path[0] = exchangeRouter.WETH();
            path[1] = token;
            exchangeRouter.swapExactETHForTokensSupportingFeeOnTransferTokens{
                value: msg.value
            }(0, path, address(this), block.timestamp + 20);
        } else {
            IWETH(token).deposit{value: msg.value}();
        }
    }

    function exchangeToken(
        address fromToken,
        address toToken,
        address exchangeRouterAddress,
        uint256 amount
    )
        private
        returns (
            uint256,
            uint256,
            uint256
        )
    {
        IUniswapV2Router02 exchangeRouter = IUniswapV2Router02(
            exchangeRouterAddress
        );
        uint256 expected;
        uint256 received;
        uint256 gas;
        address[] memory path = new address[](2);
        IERC20 token = IERC20(fromToken);
        path[0] = fromToken;
        path[1] = toToken;
        expected = exchangeRouter.getAmountsOut(amount, path)[1];
        token.approve(exchangeRouterAddress, type(uint256).max);
        gas = gasleft();
        exchangeRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
            amount,
            0,
            path,
            address(this),
            block.timestamp + 20
        );
        gas = gas - gasleft();
        token = IERC20(toToken);
        received = token.balanceOf(address(this));
        return (expected, received, gas);
    }

    function buy(
        address baseToken,
        address token,
        address exchangeRouterAddress
    )
        public
        payable
        returns (
            uint256,
            uint256,
            uint256,
            uint256,
            uint256,
            uint256
        )
    {
        IERC20 _baseToken = IERC20(baseToken);
        uint256 amount;
        ExchangeResult memory tokenRes;
        ExchangeResult memory baseTokenRes;

        deposit(baseToken, exchangeRouterAddress);
        amount = _baseToken.balanceOf(address(this));

        (tokenRes.expected, tokenRes.received, tokenRes.gas) = exchangeToken(
            baseToken,
            token,
            exchangeRouterAddress,
            amount
        );

        (
            baseTokenRes.expected,
            baseTokenRes.received,
            baseTokenRes.gas
        ) = exchangeToken(
            token,
            baseToken,
            exchangeRouterAddress,
            tokenRes.received
        );

        // Finally return all results at once    (#4)
        return (
            tokenRes.expected,
            tokenRes.received,
            tokenRes.gas,
            baseTokenRes.expected,
            baseTokenRes.received,
            baseTokenRes.gas
        );
    }
}
3
  • Thanks Patrice! This was very helpful. However, I'm running into this error while trying to deploy on BSC testnet. I have 3.9 BNB so I'm not sure what's going on. Gas estimation errored with the following message (see below). The transaction execution will likely fail. Do you want to force sending? Internal JSON-RPC error. { "code": -32000, "message": "execution reverted" } Any ideas?
    – user96723
    Mar 22, 2022 at 1:19
  • I don't know about your issue, using brownie I can deploy this contract on BSC testnet: testnet.bscscan.com/address/… Mar 24, 2022 at 21:47
  • I had 5 in the VALUE field for gas. Turns out BSC testnet does not accept gas to deploy. Changed it to 0 and it deployed. However, I haven't been successful calling the buy function (renamed to simulate_txn in the post). Could you pls take a peak? link
    – user96723
    Mar 25, 2022 at 4:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.