Here is one of the functions I am curious about...

function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
    require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
    (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
    require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');

    uint balance0;
    uint balance1;
    { // scope for _token{0,1}, avoids stack too deep errors
        address _token0 = token0;
        address _token1 = token1;
        require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
        if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
        if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
        if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
        balance0 = IERC20(_token0).balanceOf(address(this));
        balance1 = IERC20(_token1).balanceOf(address(this));
    uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
    uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
    require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
    { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
        uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
        uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
        require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');

    _update(balance0, balance1, _reserve0, _reserve1);
    emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);

As you can see, if you search for the comment // scope for token...., you will see there's another { in there.

I am wondering why it is there and what purpose it serves..


pragma solidity ^0.4.24;
contract TestStackError {
  event LogValue(uint);
  function logArg(uint a1, uint a2, uint a3, uint a4,
    uint a5, uint a6, uint a7, uint a8,
    uint a9, uint a10, uint a11, uint a12,
    uint a13, uint a14, uint a15
  ) public {
        uint a16 = 1;
        uint a17 = 2;

Why does it still say stack to deep error even though I intruduced another {} scope ?

  • Re: the question in "update", I think scoping like that was only introduced in 0.5. May 13 at 15:29

Solidity has a StackTooDeepException. This means that you can only have 16 local variables at any given time.

Scoping, in this sense, allows the contract to create local variables within a specific scope (for example, within brackets {...}), and then destroy them within that scope. The reason this is important is because the newly created/destroyed variable is no longer taking up a slot after the conclusion of the scope.

In your example, _token0 and _token1 are created and then destroyed within that scope.

You can read more in this article or this one.

  • Hi Shane, I updated my answer just now since something doesn't work as I realized Dec 30 '20 at 9:18
  • Shane, any luck with my updated question ? Dec 31 '20 at 11:30
  • Hi Shane, any way you can take a look at my updated question ? hope it's not too late Jan 29 at 21:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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