Skip to content

Instantly share code, notes, and snippets.

@imqdee
Created February 28, 2023 13:32
Show Gist options
  • Select an option

  • Save imqdee/acb25f98f7e5282e53433098c1e9bb32 to your computer and use it in GitHub Desktop.

Select an option

Save imqdee/acb25f98f7e5282e53433098c1e9bb32 to your computer and use it in GitHub Desktop.
Easy to implement solutions for the StackTooDeep error
pragma solidity >=0.8.19;
contract Test {
// This function raise a "Stack too deep" error
// The explanation for this is due to the constraints of referencing
// variables in the EVM stack. Despite the possibility of having over
// 16 variables in the stack, any attempt to reference a variable beyond slot
// 16 will result in failure. Hence, it can be difficult to identify the exact
// reason for a code's failure, and sometimes making random alterations may appear
// to resolve the issues
function stackTooDeep() external pure returns (uint256) {
uint256 a = 8;
uint256 b = a + 4;
uint256 c = b + 6;
uint256 d = c + 8;
uint256 e = d * 9;
uint256 f = e**2;
uint256 g = a + f;
uint256 h = b * c + g;
uint256 i = 2 * h;
uint256 j = i + 1;
uint256 k = c * a * b + j;
uint256 l = k + 4;
uint256 m = l * l;
uint256 n = m + 1;
uint256 o = n + n * 2;
uint256 p = c + d + o;
return p;
}
// SOLUTION #1
// Try compiling your contracts using the `--via-ir` flag
// This flag enable more powerful optimization passes that span across functions
// Sometime, it's enough
// SOLUTION #2
// Use less variables. As simple as that
function fixedUsingLessVariables() external pure returns (uint256) {
uint256 a = 8;
uint256 b = a + 4;
uint256 c = b + 6;
uint256 d = c + 8;
// 'e' is only used in f, meaning we can avoid declaring a variable in that case
// uint256 e = d * 9;
uint256 f = (d * 9)**2;
uint256 g = a + f;
// 'h' is only used by h, which means that we can avoid declaring a variable in this case
// uint256 h = b * c + g;
// 'i' is only used by j, which means that we can avoid declaring a variable in this case
//uint256 i = 2 * (b * c + g);
uint256 j = (2 * (b * c + g)) + 1;
uint256 k = c * a * b + j;
uint256 l = k + 4;
uint256 m = l * l;
uint256 n = m + 1;
uint256 o = n + n * 2;
uint256 p = c + d + o;
return p;
}
// SOLUTION #3
// you can take advantage of the "block scoping" properties (a la Diamond or Uniswap).
// Split your logic into different blocks
function fixedUsingBlockScope() external pure returns (uint256) {
uint256 result;
{
uint256 a = 8;
uint256 b = a + 4;
uint256 c = b + 6;
uint256 d = c + 8;
uint256 e = d * 9;
uint256 f = e**2;
uint256 g = a + f;
uint256 h = b * c + g;
result = h;
}
{
uint256 i = 2 * result;
uint256 j = i + 1;
uint256 k = j * i + j;
uint256 l = k + 4;
uint256 m = l * l;
uint256 n = m + 1;
uint256 o = n + n * 2;
result = result + 2 + o;
}
return result;
}
// SOLUTION #4
// The most extreme one. Take advantages of the struct
struct Store {
uint256 a;
uint256 b;
uint256 c;
uint256 d;
uint256 e;
uint256 f;
uint256 g;
uint256 h;
uint256 i;
uint256 j;
uint256 k;
uint256 l;
uint256 m;
uint256 n;
uint256 o;
uint256 p;
}
function fixedUsingStruct() external pure returns (uint256) {
Store memory store = Store(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
store.a = 8;
store.b = store.a + 4;
store.c = store.b + 6;
store.d = store.c + 8;
store.e = store.d * 9;
store.f = store.e**2;
store.g = store.a + store.f;
store.h = store.b * store.c + store.g;
store.i = 2 * store.h;
store.j = store.i + 1;
store.k = store.c * store.a * store.b + store.j;
store.l = store.k + 4;
store.m = store.l * store.l;
store.n = store.m + 1;
store.o = store.n + store.n * 2;
store.p = store.c + store.d + store.o;
return store.p;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment