diff --git a/contracts/.changeset/nice-planets-share.md b/contracts/.changeset/nice-planets-share.md new file mode 100644 index 00000000000..a8af56ac613 --- /dev/null +++ b/contracts/.changeset/nice-planets-share.md @@ -0,0 +1,5 @@ +--- +'@chainlink/contracts': minor +--- + +EnumerableMap Library for an Address to Bytes mapping diff --git a/contracts/gas-snapshots/shared.gas-snapshot b/contracts/gas-snapshots/shared.gas-snapshot index 0419c42a6aa..3cc143ecc0e 100644 --- a/contracts/gas-snapshots/shared.gas-snapshot +++ b/contracts/gas-snapshots/shared.gas-snapshot @@ -51,21 +51,29 @@ CallWithExactGas__callWithExactGasSafeReturnData:test_NoContractReverts() (gas: CallWithExactGas__callWithExactGasSafeReturnData:test_NoGasForCallExactCheckReverts() (gas: 16139) CallWithExactGas__callWithExactGasSafeReturnData:test_NotEnoughGasForCallReverts() (gas: 16547) CallWithExactGas__callWithExactGasSafeReturnData:test_callWithExactGasSafeReturnData_ThrowOOGError_Revert() (gas: 36752) -EnumerableMapAddresses_at:testAtSuccess() (gas: 95001) -EnumerableMapAddresses_at:testBytes32AtSuccess() (gas: 94770) +EnumerableMapAddresses_at:testAtSuccess() (gas: 95086) +EnumerableMapAddresses_at:testBytes32AtSuccess() (gas: 94877) EnumerableMapAddresses_contains:testBytes32ContainsSuccess() (gas: 93518) EnumerableMapAddresses_contains:testContainsSuccess() (gas: 93696) -EnumerableMapAddresses_get:testBytes32GetSuccess() (gas: 94249) -EnumerableMapAddresses_get:testGetSuccess() (gas: 94436) -EnumerableMapAddresses_get_errorMessage:testGetErrorMessageSuccess() (gas: 94477) -EnumerableMapAddresses_length:testBytes32LengthSuccess() (gas: 72404) -EnumerableMapAddresses_length:testLengthSuccess() (gas: 72582) -EnumerableMapAddresses_remove:testBytes32RemoveSuccess() (gas: 73408) +EnumerableMapAddresses_get:testBytes32GetSuccess() (gas: 94278) +EnumerableMapAddresses_get:testGetSuccess() (gas: 94453) +EnumerableMapAddresses_get_errorMessage:testGetErrorMessageSuccess() (gas: 94489) +EnumerableMapAddresses_length:testBytes32LengthSuccess() (gas: 72445) +EnumerableMapAddresses_length:testLengthSuccess() (gas: 72640) +EnumerableMapAddresses_remove:testBytes32RemoveSuccess() (gas: 73462) EnumerableMapAddresses_remove:testRemoveSuccess() (gas: 73686) EnumerableMapAddresses_set:testBytes32SetSuccess() (gas: 94496) EnumerableMapAddresses_set:testSetSuccess() (gas: 94685) -EnumerableMapAddresses_tryGet:testBytes32TryGetSuccess() (gas: 94604) -EnumerableMapAddresses_tryGet:testTryGetSuccess() (gas: 94864) +EnumerableMapAddresses_tryGet:testBytes32TryGetSuccess() (gas: 94622) +EnumerableMapAddresses_tryGet:testTryGetSuccess() (gas: 94893) +EnumerableMapAddresses_at:testBytesAtSuccess() (gas: 96564) +EnumerableMapAddresses_contains:testBytesContainsSuccess() (gas: 94012) +EnumerableMapAddresses_get:testBytesGetSuccess() (gas: 95879) +EnumerableMapAddresses_get_errorMessage:testBytesGetErrorMessageSuccess() (gas: 95878) +EnumerableMapAddresses_length:testBytesLengthSuccess() (gas: 73011) +EnumerableMapAddresses_remove:testBytesRemoveSuccess() (gas: 74249) +EnumerableMapAddresses_set:testBytesSetSuccess() (gas: 95428) +EnumerableMapAddresses_tryGet:testBytesTryGetSuccess() (gas: 96279) OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1743649) OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 298649) OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957) diff --git a/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol b/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol index 6fbd37c60d7..c14a03b4443 100644 --- a/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol +++ b/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol @@ -1,12 +1,15 @@ // SPDX-License-Identifier: MIT +/* solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore */ pragma solidity ^0.8.0; import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; +import {EnumerableMapBytes32} from "./EnumerableMapBytes32.sol"; // TODO: the lib can be replaced with OZ v5.1 post-upgrade, which has AddressToAddressMap and AddressToBytes32Map library EnumerableMapAddresses { using EnumerableMap for EnumerableMap.UintToAddressMap; using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map; + using EnumerableMapBytes32 for EnumerableMapBytes32.Bytes32ToBytesMap; struct AddressToAddressMap { EnumerableMap.UintToAddressMap _inner; @@ -57,8 +60,6 @@ library EnumerableMapAddresses { return map._inner.get(uint256(uint160(key)), errorMessage); } - // AddressToBytes32Map - struct AddressToBytes32Map { EnumerableMap.Bytes32ToBytes32Map _inner; } @@ -137,4 +138,88 @@ library EnumerableMapAddresses { function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) { return map._inner.get(bytes32(uint256(uint160(key)))); } + + struct AddressToBytesMap { + EnumerableMapBytes32.Bytes32ToBytesMap _inner; + } + + /** + * @dev Sets the value for `key` in the map. Returns true if the key was added to the map, that is if it was not already present. + * @param map The map where the value will be set + * @param key The key to set the value for + * @param value The value to set for the key + * @return bool indicating whether the key was added to the map + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function set(AddressToBytesMap storage map, address key, bytes memory value) internal returns (bool) { + return map._inner.set(bytes32(uint256(uint160(key))), value); + } + + /** + * @dev Removes the value for `key` in the map. Returns true if the key was removed from the map, that is if it was present. + * @param map The map where the value will be removed + * @param key The key to remove the value for + * @return bool indicating whether the key was removed from the map + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function remove(AddressToBytesMap storage map, address key) internal returns (bool) { + return map._inner.remove(bytes32(uint256(uint160(key)))); + } + + /** + * @dev Checks if the map contains the `key`. Returns true if the key is in the map. + * @param map The map to check for the presence of the key + * @param key The key to check for presence in the map + * @return bool indicating whether the key is in the map + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function contains(AddressToBytesMap storage map, address key) internal view returns (bool) { + return map._inner.contains(bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns the number of elements in the map. + * @param map The map to check the length of + * @return uint256 indicating the number of elements in the map + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function length(AddressToBytesMap storage map) internal view returns (uint256) { + return map._inner.length(); + } + + /** + * @dev Returns the element stored at position `index` in the map. 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. + * @param map The map to retrieve the element from + * @param index The index to retrieve the element at + * @return address The key of the element at the specified index + * @return bytes The value of the element at the specified index + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function at(AddressToBytesMap storage map, uint256 index) internal view returns (address, bytes memory) { + (bytes32 key, bytes memory value) = map._inner.at(index); + return (address(uint160(uint256(key))), value); + } + + /** + * @dev Tries to return the value associated with `key`. Does not revert if `key` is not in the map. + * @param map The map to retrieve the value from + * @param key The key to retrieve the value for + * @return bool indicating whether the key was in the map + * @return bytes The value associated with the key + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function tryGet(AddressToBytesMap storage map, address key) internal view returns (bool, bytes memory) { + return map._inner.tryGet(bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns the value associated with `key`. + * @param map The map to retrieve the value from + * @param key The key to retrieve the value for + * @return bytes The value associated with the key + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function get(AddressToBytesMap storage map, address key) internal view returns (bytes memory) { + return map._inner.get(bytes32(uint256(uint160(key)))); + } } diff --git a/contracts/src/v0.8/shared/enumerable/EnumerableMapBytes32.sol b/contracts/src/v0.8/shared/enumerable/EnumerableMapBytes32.sol new file mode 100644 index 00000000000..2ec9098f855 --- /dev/null +++ b/contracts/src/v0.8/shared/enumerable/EnumerableMapBytes32.sol @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: MIT +/* solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore */ +pragma solidity ^0.8.0; + +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (O(1)). + * - Entries are enumerated in O(n). No guarantees are made on the ordering. + * + * ``` + * contract Example { + * // Add the library methods + * using EnumerableMapBytes32 for EnumerableMapBytes32.Bytes32ToBytesMap; + * + * // Declare a set state variable + * EnumerableMapBytes32.Bytes32ToBytesMap private myMap; + * } + * ``` + * + * The following map types are supported: + * + * - `bytes32 -> bytes` (`Bytes32ToBytes`) + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean up an EnumerableMapBytes32, you should remove all elements one by one. + * ==== + */ +library EnumerableMapBytes32 { + using EnumerableSet for EnumerableSet.Bytes32Set; + + error NonexistentKeyError(); + + struct Bytes32ToBytesMap { + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 => bytes) _values; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function set(Bytes32ToBytesMap storage map, bytes32 key, bytes memory value) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function remove(Bytes32ToBytesMap storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function contains(Bytes32ToBytesMap storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function length(Bytes32ToBytesMap storage map) internal view returns (uint256) { + return map._keys.length(); + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function at(Bytes32ToBytesMap storage map, uint256 index) internal view returns (bytes32, bytes memory) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function tryGet(Bytes32ToBytesMap storage map, bytes32 key) internal view returns (bool, bytes memory) { + bytes memory value = map._values[key]; + if (value.length == 0) { + return (contains(map, key), bytes("")); + } else { + return (true, value); + } + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore + function get(Bytes32ToBytesMap storage map, bytes32 key) internal view returns (bytes memory) { + bytes memory value = map._values[key]; + if (value.length == 0 && !contains(map, key)) { + revert NonexistentKeyError(); + } + return value; + } +} diff --git a/contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol b/contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol index 900c546f66d..097e79e372e 100644 --- a/contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol +++ b/contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol @@ -7,11 +7,14 @@ import {EnumerableMapAddresses} from "../../enumerable/EnumerableMapAddresses.so contract EnumerableMapAddressesTest is BaseTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; EnumerableMapAddresses.AddressToAddressMap internal s_addressToAddressMap; EnumerableMapAddresses.AddressToBytes32Map internal s_addressToBytes32Map; + EnumerableMapAddresses.AddressToBytesMap internal s_addressToBytesMap; bytes32 internal constant MOCK_BYTES32_VALUE = bytes32(uint256(42)); + bytes internal constant MOCK_BYTES_VALUE = "0x123456789abcdef"; function setUp() public virtual override { BaseTest.setUp(); @@ -21,6 +24,7 @@ contract EnumerableMapAddressesTest is BaseTest { contract EnumerableMapAddresses_set is EnumerableMapAddressesTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; function testSetSuccess() public { assertTrue(!s_addressToAddressMap.contains(address(this))); @@ -35,11 +39,19 @@ contract EnumerableMapAddresses_set is EnumerableMapAddressesTest { assertTrue(s_addressToBytes32Map.contains(address(this))); assertTrue(!s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE)); } + + function testBytesSetSuccess() public { + assertTrue(!s_addressToBytesMap.contains(address(this))); + assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + assertTrue(s_addressToBytesMap.contains(address(this))); + assertTrue(!s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + } } contract EnumerableMapAddresses_remove is EnumerableMapAddressesTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; function testRemoveSuccess() public { assertTrue(!s_addressToAddressMap.contains(address(this))); @@ -58,11 +70,21 @@ contract EnumerableMapAddresses_remove is EnumerableMapAddressesTest { assertTrue(!s_addressToBytes32Map.contains(address(this))); assertTrue(!s_addressToBytes32Map.remove(address(this))); } + + function testBytesRemoveSuccess() public { + assertTrue(!s_addressToBytesMap.contains(address(this))); + assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + assertTrue(s_addressToBytesMap.contains(address(this))); + assertTrue(s_addressToBytesMap.remove(address(this))); + assertTrue(!s_addressToBytesMap.contains(address(this))); + assertTrue(!s_addressToBytesMap.remove(address(this))); + } } contract EnumerableMapAddresses_contains is EnumerableMapAddressesTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; function testContainsSuccess() public { assertTrue(!s_addressToAddressMap.contains(address(this))); @@ -75,55 +97,81 @@ contract EnumerableMapAddresses_contains is EnumerableMapAddressesTest { assertTrue(s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE)); assertTrue(s_addressToBytes32Map.contains(address(this))); } + + function testBytesContainsSuccess() public { + assertTrue(!s_addressToBytesMap.contains(address(this))); + assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + assertTrue(s_addressToBytesMap.contains(address(this))); + } } contract EnumerableMapAddresses_length is EnumerableMapAddressesTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; function testLengthSuccess() public { - assertTrue(s_addressToAddressMap.length() == 0); + assertEq(s_addressToAddressMap.length(), 0); assertTrue(s_addressToAddressMap.set(address(this), address(this))); - assertTrue(s_addressToAddressMap.length() == 1); + assertEq(s_addressToAddressMap.length(), 1); assertTrue(s_addressToAddressMap.remove(address(this))); - assertTrue(s_addressToAddressMap.length() == 0); + assertEq(s_addressToAddressMap.length(), 0); } function testBytes32LengthSuccess() public { - assertTrue(s_addressToBytes32Map.length() == 0); + assertEq(s_addressToBytes32Map.length(), 0); assertTrue(s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE)); - assertTrue(s_addressToBytes32Map.length() == 1); + assertEq(s_addressToBytes32Map.length(), 1); assertTrue(s_addressToBytes32Map.remove(address(this))); - assertTrue(s_addressToBytes32Map.length() == 0); + assertEq(s_addressToBytes32Map.length(), 0); + } + + function testBytesLengthSuccess() public { + assertEq(s_addressToBytesMap.length(), 0); + assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + assertEq(s_addressToBytesMap.length(), 1); + assertTrue(s_addressToBytesMap.remove(address(this))); + assertEq(s_addressToBytesMap.length(), 0); } } contract EnumerableMapAddresses_at is EnumerableMapAddressesTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; function testAtSuccess() public { - assertTrue(s_addressToAddressMap.length() == 0); + assertEq(s_addressToAddressMap.length(), 0); assertTrue(s_addressToAddressMap.set(address(this), address(this))); - assertTrue(s_addressToAddressMap.length() == 1); + assertEq(s_addressToAddressMap.length(), 1); (address key, address value) = s_addressToAddressMap.at(0); - assertTrue(key == address(this)); - assertTrue(value == address(this)); + assertEq(key, address(this)); + assertEq(value, address(this)); } function testBytes32AtSuccess() public { - assertTrue(s_addressToBytes32Map.length() == 0); + assertEq(s_addressToBytes32Map.length(), 0); assertTrue(s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE)); - assertTrue(s_addressToBytes32Map.length() == 1); + assertEq(s_addressToBytes32Map.length(), 1); (address key, bytes32 value) = s_addressToBytes32Map.at(0); - assertTrue(key == address(this)); - assertTrue(value == MOCK_BYTES32_VALUE); + assertEq(key, address(this)); + assertEq(value, MOCK_BYTES32_VALUE); + } + + function testBytesAtSuccess() public { + assertEq(s_addressToBytesMap.length(), 0); + assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + assertEq(s_addressToBytesMap.length(), 1); + (address key, bytes memory value) = s_addressToBytesMap.at(0); + assertEq(key, address(this)); + assertEq(value, MOCK_BYTES_VALUE); } } contract EnumerableMapAddresses_tryGet is EnumerableMapAddressesTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; function testTryGetSuccess() public { assertTrue(!s_addressToAddressMap.contains(address(this))); @@ -131,7 +179,7 @@ contract EnumerableMapAddresses_tryGet is EnumerableMapAddressesTest { assertTrue(s_addressToAddressMap.contains(address(this))); (bool success, address value) = s_addressToAddressMap.tryGet(address(this)); assertTrue(success); - assertTrue(value == address(this)); + assertEq(value, address(this)); } function testBytes32TryGetSuccess() public { @@ -140,37 +188,62 @@ contract EnumerableMapAddresses_tryGet is EnumerableMapAddressesTest { assertTrue(s_addressToBytes32Map.contains(address(this))); (bool success, bytes32 value) = s_addressToBytes32Map.tryGet(address(this)); assertTrue(success); - assertTrue(value == MOCK_BYTES32_VALUE); + assertEq(value, MOCK_BYTES32_VALUE); + } + + function testBytesTryGetSuccess() public { + assertTrue(!s_addressToBytesMap.contains(address(this))); + assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + assertTrue(s_addressToBytesMap.contains(address(this))); + (bool success, bytes memory value) = s_addressToBytesMap.tryGet(address(this)); + assertTrue(success); + assertEq(value, MOCK_BYTES_VALUE); } } contract EnumerableMapAddresses_get is EnumerableMapAddressesTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; function testGetSuccess() public { assertTrue(!s_addressToAddressMap.contains(address(this))); assertTrue(s_addressToAddressMap.set(address(this), address(this))); assertTrue(s_addressToAddressMap.contains(address(this))); - assertTrue(s_addressToAddressMap.get(address(this)) == address(this)); + assertEq(s_addressToAddressMap.get(address(this)), address(this)); } function testBytes32GetSuccess() public { assertTrue(!s_addressToBytes32Map.contains(address(this))); assertTrue(s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE)); assertTrue(s_addressToBytes32Map.contains(address(this))); - assertTrue(s_addressToBytes32Map.get(address(this)) == MOCK_BYTES32_VALUE); + assertEq(s_addressToBytes32Map.get(address(this)), MOCK_BYTES32_VALUE); + } + + function testBytesGetSuccess() public { + assertTrue(!s_addressToBytesMap.contains(address(this))); + assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + assertTrue(s_addressToBytesMap.contains(address(this))); + assertEq(s_addressToBytesMap.get(address(this)), MOCK_BYTES_VALUE); } } contract EnumerableMapAddresses_get_errorMessage is EnumerableMapAddressesTest { using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map; using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap; + using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap; function testGetErrorMessageSuccess() public { assertTrue(!s_addressToAddressMap.contains(address(this))); assertTrue(s_addressToAddressMap.set(address(this), address(this))); assertTrue(s_addressToAddressMap.contains(address(this))); - assertTrue(s_addressToAddressMap.get(address(this), "EnumerableMapAddresses: nonexistent key") == address(this)); + assertEq(s_addressToAddressMap.get(address(this), "EnumerableMapAddresses: nonexistent key"), address(this)); + } + + function testBytesGetErrorMessageSuccess() public { + assertTrue(!s_addressToBytesMap.contains(address(this))); + assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE)); + assertTrue(s_addressToBytesMap.contains(address(this))); + assertEq(s_addressToBytesMap.get(address(this)), MOCK_BYTES_VALUE); } }