EnumerableSet EnumerableMap libraries for bytes32

I’m trying to use EnumerableSet with bytes32 and EnumerableMap libraries with a bytes32 key to address

How are the libraries supposed to be used for bytes32? create another implementation below the current “internal functions” ?

I ask because I don’t know if libraries are redeployed on every project or they have an address that any project can use.

:computer: Environment
truffle 6
node 13
ubuntu 18
solidity 6

pragma solidity ^0.6.7;

import "@openzeppelin/contracts/utils/EnumerableSet.sol";

contract LOPPoolFactory {
            using EnumerableSet for EnumerableSet.AddressSet; 
            using EnumerableSet for EnumerableSet.bytes32Set;  
            
            //Currencies that are available to pool
            EnumerableSet.AddressSet private underlyingAcceptedCurrencies; //AddresSet exists 
            EnumerableSet.bytes32Set private providers;   //bytes32Set does not exists 

           //@notice add a provider
            function addProvider(bytes32 provider) public returns (bool) {
                       providers.add(provider); //currently
            }

My question is why in EnumerableSet and EnumerableMap there are no implementations for all types that are supported by bytes32? Is it because every project has their own library contract ? I thought a library was supposed to be public address that myriad of unrelated contracts call

1 Like

Hi @cyril-attie,

Internal library functions are included at compile time in the calling contract. Which means that for libraries only containing internal functions the library doesn't get deployed separately. See the Solidity documentation for details:

https://solidity.readthedocs.io/en/v0.6.8/contracts.html#libraries

Libraries are similar to contracts, but their purpose is that they are deployed only once at a specific address and their code is reused using the DELEGATECALL ( CALLCODE until Homestead) feature of the EVM.

To realize this in the EVM, code of internal library functions and all functions called from therein will at compile time be included in the calling contract, and a regular JUMP call will be used instead of a DELEGATECALL .

As for creating EnumberableSet + EnumberableMap libraries for bytes32, please see the following post in the forum:

Hi @cyril-attie,

Checking to see how you got on? Please ask all the questions that you need.

Hi Andrew!

Thanks for the clarification! I ended up copying the enumerableSet.sol in a /contracts/libraries and adding an implementation for bytes32Set:

   struct bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

Would you have done differently? How?

1 Like

Hi @cyril-attie,

Unfortunately until we have generics / templates in Solidity then I don’t think there is a better way than copying and changing the type. I don’t think it is practical for OpenZeppelin Contracts to have a variation for every type until we have generics / templates.

Please can you add the MIT license and a reference to the original file to the top of your EnumerableSet:

// SPDX-License-Identifier: MIT
// Based on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.1/contracts/utils/EnumerableSet.sol

There is an open issue for Solidity for templates / generics that I suggest following: