0

I have two libraries: A and B as well as contract C using them.

Library B, in one of its functions, needs to call a couple of functions defined for A.Storage.

The code below compiles, tests are passing, but I have no idea how should I interpret storage modifier when passing library as a parameter: A.Storage storage a. Is this setup safe? Am I referencing the memory of contract C and not creating a copy of A.Storage?

From what I tested, passing A.Storage memory a does not work, the compiler complains:

TypeError: Member "someFuncDefinedForA" is not available in struct A.Storage memory outside of storage.

library A {
  struct Storage { ... }
}

library B {
  using A for A.Storage;

  struct Storage { ... }

  function myFunc(
      Storage storage self,
      A.Storage storage a // <-- ?
  ) public { 
    // (...)
    a.someFuncDefinedForA();
  }
}

contract C {
  using A for A.Storage;
  using B for B.Storage;

  A.Storage internal a;
  B.Storage internal b;

  function doIt() public {
    b.myFunc(a);
  }
}
2
  • What version of solc are you using? Do both A and B define the same struct or a different one with same name? It should be possible to use either storage or memory. If the functions are public you will need the ABIEncoderV2.
    – Ismael
    Jun 30 '20 at 20:49
  • solc 0.5.17, A and B define different structs; myFunc is public and surprisingly solc does not complain about ABIEncoderV2. Maybe because it's just a library function accessed via DELEGATECALL?
    – omnomnom
    Jul 1 '20 at 8:43
1

Neither B nor A have storage of their own, they use the storage provided by C.

I write a code similar and it works with both storage and memory.

pragma solidity ^0.5.0;

library A {
    
    struct S {
        uint256 a;
    }
    
    function foo(A.S memory a) internal view returns (uint256) {
        return a.a;
    }
}

library B {
    
    using A for A.S;
    
    struct T {
        uint256 b;
    }
    
    function bar(B.T memory t, A.S memory s) internal view returns (uint256) {
        return s.foo() * 1000 + t.b;
    }
}

contract C {
    using B for B.T;
    
    A.S public k;
    B.T public l;
    
    function baz() public returns (uint256) {
        k = A.S(121);
        l = B.T(333);
        return l.bar(k);
    }
    
}

2
  • Just to make sure - if I want to have B.bar public so that the code is not copied into C but accessed via DELEGATECALL, I should enable ABIEncoderV2?
    – omnomnom
    Jul 6 '20 at 4:14
  • 1
    @omnomnom With memory modifier both solc v0.5 and v0.6 require pragma experimental ABIEncoderV2 to compile. With storage modifier it is not required.
    – Ismael
    Jul 6 '20 at 13:04

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.