4

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 &amp;&amp; to != _token1, 'UniswapV2: INVALID_TO');
    if (amount0Out &gt; 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
    if (amount1Out &gt; 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
    if (data.length &gt; 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
    balance0 = IERC20(_token0).balanceOf(address(this));
    balance1 = IERC20(_token1).balanceOf(address(this));
}
uint amount0In = balance0 &gt; _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
uint amount1In = balance1 &gt; _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
require(amount0In &gt; 0 || amount1In &gt; 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) &gt;= 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..

UPDATE:

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 ?

Nika Kurashvili
  • 1,175
  • 1
  • 10
  • 25

1 Answers1

5

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.

Shane Fontaine
  • 18,036
  • 20
  • 54
  • 82