4

I have Very Interesting cases about Libraries.

CASE 1:

I read the following in the official solidity docs:

Library functions can only be called directly (i.e. without the use of DELEGATECALL) if they do not modify the state (i.e. if they are view or pure functions), because libraries are assumed to be stateless

I am sure they mean to call libraries with the use of .call on the address and they say this would only be possible if the function of the libraries would be pure/view. Let me reprase in the a), b), c) what I don't understand.

a) In the copied sentence, It says: if they do not modify the state. I am not sure how the library changes state at all. it doesn't have its own and all it can do is change the passed variable's value.

b) I tried using it with addr.call, but I didn't specify functions as pure/view and it still let me do this. It's interesting why it let me since in the docs, it says it should revert.

c) Why would I ever want to call libraries with the .call ? This just defeats the whole purpose of libraries.

**D) ** It seems like if I use internal functions on libraries, the library code ends up in the compiled version of the contract. Any reason why this is good ? if that's so, I'd have used another contract instead of library.

Case 2:

In the docs, It's really a bad example how it passes the reference type. Let's say I have a library:

// Let's say this was written by third-party and it's put on github.

library libraryContract {
   
   function libraryTest(){

   }

}

// I can import the above here.

// import "libraryContract.sol";

contract myContract {
   
   function contractTest(){
      // I call it. This will work. Now, let's say in this contract, I
      // have a variable called `uint x = 0;`. and what libraryContract 
      // should be doing is change the value of the passed argument. 
      // If I pass `x` here directly, and change the argument in 
      //`libraryTest`, It still doesn't work since it's not passed by 
      //reference or something. Another case is What If I want my library 
      //to be changing the struct's properties, but library doesn't see 
      //the definiton of struct. 
      libraryContract.test(); 
   }

}

1
  • Libraries once deployed are just like any other contract. AFAIK there's nothing that prevents any user calling the functions. The internal functions are meant to be called from within the same contract, making them callable from another contract defeat the purpose of being internal. Libraries are good for organizing the code but they have some limitations. If the solidity docs aren't clear I'd suggest to ask solidity developers.
    – Ismael
    Jan 26, 2021 at 2:49

3 Answers 3

2

It seems like if I use internal functions on libraries, the library code ends up in the compiled version of the contract

One application for this is reusable code. For example SafeMath uses internal functions. This way, when you do a.add(b), it does the computation without using a delegatecall. If a delegatecall were to be used, the computations will end up being quite expensive.

However, in the future, this usage of libraries will likely become less prevalent because of free functions.


A simple example of the "state issue" would be:

library L {
    function f() external {
        assembly {
            sstore(0, 1)
        }
    }
}

So if there was no call protection, then you would be writing to the library's state.

1

a) In the copied sentence, It says: if they do not modify the state. I am not sure how the library changes state at all. it doesn't have its own and all it can do is change the passed variable's value.

A library can change the state of a calling contract through a delegatecall. In this case, the function is executed as though it were written directly in the calling contract. This means it can in theory modify any part of the calling contract's state, so long the corresponding variables have been declared in the library, (but not initialized, since the library has no state of its own). What the docs are saying is that if you try to call such a function directly, it will fail, as it is not intended to change/modify its own storage (because no such storage exists), rather, the corresponding storage on a calling contract.

b) I tried using it with addr.call, but I didn't specify functions as pure/view and it still let me do this. It's interesting why it let me since in the docs, it says it should revert.

Marking a function as pure / view is not compulsory, so as long as the function doesn't actually try to modify state, the transaction will not revert.

c) Why would I ever want to call libraries with the .call ? This just defeats the whole purpose of libraries.

A library can be used to modify the state of a calling contract (via delegatecall), but it can also behave like a class with static methods. For example, let's say you always find yourself needing some familiar constants or methods in your contracts (uint pi, uint days_in_year function n_squared(uint n), etc.). You can factor them out to a library to avoid having to include them in every contract you write. Then they are only stored once on the blockchain, and the other contracts just call them when they need them.

3
  • Thanks Simon. I have a couple of points here too. Jan 28, 2021 at 21:32
  • 1). You say: not initialised . It means that the only thing I can put in library is struct, because if I put ints or array or anything else, it means they get initialized by default. 3). It seems to be that what example you brought about n_squared can also be done by just uploading a contract instead of library and then using its functions. Also, I could call the contract's method with my own delegatecall. So, I still don't see big picture maybe Jan 28, 2021 at 21:35
  • Heyy, as you said it can in theory modify any part of the calling contract's state. What does in theory mean here? Can I really change the contract's address? Apr 5 at 16:41
0

Libraries are stateless, they can store only 'constant' values. So even if delegatecall is used on library it wont be able to change the state of caller contract.

For example when i tried to create below library, it gives this error:

from solidity: TypeError: Library cannot have non-constant state variables

library LibraryContract {

  uint storedTime;  

  function setTime(uint _time) public {
    storedTime = _time;
  }
}

Update: Turns out this restriction is lifted when used in the way this article mentions: https://dev.to/mudgen/solidity-libraries-can-t-have-state-variables-oh-yes-they-can-3ke9

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.