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, 2020 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, 2020 at 8:43

1 Answer 1

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, 2020 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, 2020 at 13:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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