// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.6.11; // ============ External Imports ============ import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; // ============ Internal Imports ============ import {TypeCasts} from "./TypeCasts.sol"; enum EnrollmentStatus { UNENROLLED, ENROLLED, PENDING_UNENROLLMENT } struct Enrollment { EnrollmentStatus status; uint248 unenrollmentStartBlock; } // extends EnumerableMap with address => bytes32 type // modelled after https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.0/contracts/utils/structs/EnumerableMap.sol library EnumerableMapEnrollment { using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map; using EnumerableSet for EnumerableSet.Bytes32Set; using TypeCasts for address; using TypeCasts for bytes32; struct AddressToEnrollmentMap { EnumerableMap.Bytes32ToBytes32Map _inner; } // ============ Library Functions ============ function encode( Enrollment memory enrollment ) public pure returns (bytes32) { return bytes32( abi.encodePacked( uint8(enrollment.status), enrollment.unenrollmentStartBlock ) ); } function decode(bytes32 encoded) public pure returns (Enrollment memory) { uint8 status = uint8(encoded[0]); uint248 unenrollmentStartBlock = uint248(uint256((encoded << 8) >> 8)); return Enrollment(EnrollmentStatus(status), unenrollmentStartBlock); } function keys( AddressToEnrollmentMap storage map ) internal view returns (address[] memory _keys) { uint256 _length = map._inner.length(); _keys = new address[](_length); for (uint256 i = 0; i < _length; i++) { _keys[i] = address(uint160(uint256(map._inner._keys.at(i)))); } } function set( AddressToEnrollmentMap storage map, address key, Enrollment memory value ) internal returns (bool) { return map._inner.set(key.addressToBytes32(), encode(value)); } function get( AddressToEnrollmentMap storage map, address key ) internal view returns (Enrollment memory) { return decode(map._inner.get(key.addressToBytes32())); } function tryGet( AddressToEnrollmentMap storage map, address key ) internal view returns (bool, Enrollment memory) { (bool success, bytes32 value) = map._inner.tryGet( key.addressToBytes32() ); return (success, decode(value)); } function remove( AddressToEnrollmentMap storage map, address key ) internal returns (bool) { return map._inner.remove(key.addressToBytes32()); } function contains( AddressToEnrollmentMap storage map, address key ) internal view returns (bool) { return map._inner.contains(key.addressToBytes32()); } function length( AddressToEnrollmentMap storage map ) internal view returns (uint256) { return map._inner.length(); } function at( AddressToEnrollmentMap storage map, uint256 index ) internal view returns (uint256, Enrollment memory) { (bytes32 key, bytes32 value) = map._inner.at(index); return (uint256(key), decode(value)); } }