I was reading about libraries and came to articles saying library cant have storage.
But I have seen libraries where storage keyword has been used.
Example:
in Aave protocol v3
function calculateUserAccountData(
address user,
mapping(address => DataTypes.ReserveData) storage reservesData,
DataTypes.UserConfigurationMap memory userConfig,
mapping(uint256 => address) storage reserves,
uint256 reservesCount,
address oracle
)
internal
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256
)
{
...........
DataTypes.ReserveData storage currentReserve = reservesData[vars.currentReserveAddress];
Does this mean that in internal functions storage can be used as the functions are imported from the library?
Am I missing something?
Best Answer
It's not that the storage keyword is forbidden in libraries, it's that they cannot have state variables of their own, because they are stateless.
A state variable is declared at the Contract scope level, hence it is part of the global state of the Contract.
A local storage variable is declared at the function scope level, it is part of the "function's state" as long as the function is executing, then this variable is discarded. The important point is that the local storage variable itself may very well be a reference, so, discarding it doesn't mean that what it refers to is also discarded.
So this is forbidden :
Because
stateVariable
is well.. a state variable since it is declared at the contract / library level. The compilation fails withTypeError: Library cannot have non-constant state variables
as expected.The code you provided on the other hand is different, receiving a
storage
parameter only really make sense if that parameter is a state variable of the calling contract. This is a reference to the caller's state variable, allowing the library function to read / write the calling contract's storage.Those library calls are actually compiled with
delegatecall
if the library is deployed, if the library is embedded it will simply be included in the contract's code. Your example is an embedded library if I'm not wrong, but it doesn't really matter.The second usage :
Simply creates a storage variable that is a direct reference to
reservesData[vars.currentReserveAddress]
.From the documentation :
Now I might have missed something but it really seems to me like this is just a way to avoid writing
reservesData[vars.currentReserveAddress]
to access that variable. It can now be accessed withcurrentReserve
.The point is that this is also not a state variable of the library, it's only a reference to a storage variable that belongs to the caller's storage / state.
Maybe a more precise example with read / write such as this one is a better way to fully answer your question regarding storage parameters / variables with (linked) libraries :
The contract is giving storage references of its own state variables to the library so that the library may act on it. The library never had a state variable of its own, it is however allowed to act on the state variable(s) of the contract that is calling it if it is given references to it as parameter.
I hope that answers your question.