7

I know that this has been covered in other questions here but I'm not sure what's happening in my case. My code is returning a compiler error "Stack too deep, try removing local variables." But I only have around five function arguments and a few more local variables. The function in question is given below:

function sell(bool limit, uint256 whichquery, uint8 whichoutcome, uint256 amount, uint16 price) {
        uint cumulativeamountgained;
        uint numorderstobedeleted;
        uint amountnotfilled = amount;
        if(tokenHoldings[msg.sender][whichquery][whichoutcome] < amount) throw;
        if(limit){
            for (uint i=orderbook[whichquery][whichoutcome][0].length-1;i>=0;i--){
                if(orderbook[whichquery][whichoutcome][0][i][0] >= price) {
                    if(orderbook[whichquery][whichoutcome][0][i][1] > amountnotfilled){
                        orderbook[whichquery][whichoutcome][0][i][1] -= amountnotfilled;
                        tokenHoldings[address(orderbook[whichquery][whichoutcome][0][i][2])][whichquery][whichoutcome] += amountnotfilled;

The error is triggered on the last line of this code snippet under the first "whichquery".

7

The limit of having not more than 16 local variables could be a problem here. You can try to refactor your code and probably break this function into two parts. That should fix the issue I hope.

Please read the article Solidity stack too deep by James Carlyle to understand more about this issue.

| improve this answer | |
2

Found nice trick to avoid "Stack too deep" issue:

function swapWithReferral(
    IERC20 fromToken,
    IERC20 destToken,
    uint256 amount,
    uint256 minReturn,
    uint256[] calldata distribution,
    uint256 flags,
    address referral,
    uint256 feePercent
) external makeGasDiscount(flags) returns(uint256 returnAmount) {
    ...
    fromToken.transferFrom(address(this), amount); // <-- Stack too deep
    ...
    destToken.transfer(msg.sender, returnAmount);  // <-- Stack too deep
    ...
}

Just define few additional internal functions like _fromToken() and _destToken() to decode args:

// Helps to avoid "Stack too deep" in swap() method
function _fromToken(bytes memory data) internal pure returns(IERC20 token) {
    assembly {
        token := mload(add(data, 36))
    }
}

// Helps to avoid "Stack too deep" in swap() method
function _destToken(bytes memory data) internal pure returns(IERC20 token) {
    assembly {
        token := mload(add(data, 68))
    }
}

And use these functions instead of access to those vars:

function swapWithReferral(
    IERC20 /*fromToken*/,
    IERC20 /*destToken*/,
    uint256 amount,
    uint256 minReturn,
    uint256[] calldata distribution,
    uint256 flags,
    address referral,
    uint256 feePercent
) external makeGasDiscount(flags) returns(uint256 returnAmount) {
    ...
    _fromToken(msg.sender).transferFrom(address(this), amount); // Works great!
    ...
    _destToken(msg.sender).transfer(msg.sender, returnAmount);  // Works great!
    ...
}

Notice: Be careful with internal and public functions, since msg.data is updated only on external calls. You can externally call public function with this.doSomething().

| improve this answer | |
1

there is limited amount of local variables you are allowed to declare in your function(arguments and return types inclusive), i think it is 16, but as it seems you have exceeded that limit.

| improve this answer | |
  • Yip. It's 16 fixed length fields. Strings take two slots, so 8 strings. – Rob Hitchens Jul 7 '17 at 0:08
1

You can also scope variables like this

uint var1;
{
    (uint varA, uint varB) = getVars();
    var1 = varA + varB;
}

// now use var1

Inspired by Uniswap.

| improve this answer | |
  • This worked for me. It's a really nice, clean workaround. – Michael Connor Aug 24 at 15:44

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.