Skip to content

Commit

Permalink
feat: CCIP-2465 use EnumerableMapBytes32 library for address -> bytes…
Browse files Browse the repository at this point in the history
… mapping
  • Loading branch information
defistar committed Aug 12, 2024
1 parent 83f9b2f commit bd1e9a6
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 75 deletions.
6 changes: 3 additions & 3 deletions contracts/src/v0.8/ccip/MultiAggregateRateLimiter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ contract MultiAggregateRateLimiter is IMessageInterceptor, AuthorizedCallers {
remoteTokens = new bytes[](tokenCount);

for (uint256 i = 0; i < tokenCount; ++i) {
(address localToken, bytes memory remoteToken) = s_rateLimitedTokensLocalToRemote[remoteChainSelector]._at(i);
(address localToken, bytes memory remoteToken) = s_rateLimitedTokensLocalToRemote[remoteChainSelector].at(i);
localTokens[i] = localToken;
remoteTokens[i] = remoteToken;
}
Expand All @@ -226,7 +226,7 @@ contract MultiAggregateRateLimiter is IMessageInterceptor, AuthorizedCallers {
address localToken = removes[i].localToken;
uint64 remoteChainSelector = removes[i].remoteChainSelector;

if (s_rateLimitedTokensLocalToRemote[remoteChainSelector]._remove(localToken)) {
if (s_rateLimitedTokensLocalToRemote[remoteChainSelector].remove(localToken)) {
emit TokenAggregateRateLimitRemoved(remoteChainSelector, localToken);
}
}
Expand All @@ -244,7 +244,7 @@ contract MultiAggregateRateLimiter is IMessageInterceptor, AuthorizedCallers {

uint64 remoteChainSelector = localTokenArgs.remoteChainSelector;

if (s_rateLimitedTokensLocalToRemote[remoteChainSelector]._set(localToken, remoteToken)) {
if (s_rateLimitedTokensLocalToRemote[remoteChainSelector].set(localToken, remoteToken)) {
emit TokenAggregateRateLimitAdded(remoteChainSelector, remoteToken, localToken);
}
}
Expand Down
56 changes: 0 additions & 56 deletions contracts/src/v0.8/shared/enumerable/CCIPEnumerableMap.sol

This file was deleted.

37 changes: 21 additions & 16 deletions contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol
Original file line number Diff line number Diff line change
@@ -1,14 +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 {CCIPEnumerableMap} from "./CCIPEnumerableMap.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 CCIPEnumerableMap for CCIPEnumerableMap.Bytes32ToBytesMap;
using EnumerableMapBytes32 for EnumerableMapBytes32.Bytes32ToBytesMap;

struct AddressToAddressMap {
EnumerableMap.UintToAddressMap _inner;
Expand Down Expand Up @@ -59,8 +60,6 @@ library EnumerableMapAddresses {
return map._inner.get(uint256(uint160(key)), errorMessage);
}

// AddressToBytes32Map

struct AddressToBytes32Map {
EnumerableMap.Bytes32ToBytes32Map _inner;
}
Expand Down Expand Up @@ -141,7 +140,7 @@ library EnumerableMapAddresses {
}

struct AddressToBytesMap {
CCIPEnumerableMap.Bytes32ToBytesMap _inner;
EnumerableMapBytes32.Bytes32ToBytesMap _inner;
}

/**
Expand All @@ -151,8 +150,9 @@ library EnumerableMapAddresses {
* @param value The value to set for the key
* @return bool indicating whether the key was added to the map
*/
function _set(AddressToBytesMap storage map, address key, bytes memory value) internal returns (bool) {
return map._inner._set(bytes32(uint256(uint160(key))), value);
// 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);
}

/**
Expand All @@ -161,8 +161,9 @@ library EnumerableMapAddresses {
* @param key The key to remove the value for
* @return bool indicating whether the key was removed from the map
*/
function _remove(AddressToBytesMap storage map, address key) internal returns (bool) {
return map._inner._remove(bytes32(uint256(uint160(key))));
// 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))));
}

/**
Expand All @@ -171,17 +172,19 @@ library EnumerableMapAddresses {
* @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))));
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();
return map._inner.length();
}

/**
Expand All @@ -191,8 +194,9 @@ library EnumerableMapAddresses {
* @return address The key of the element at the specified index
* @return bytes The value of the element at the specified index
*/
function _at(AddressToBytesMap storage map, uint256 index) internal view returns (address, bytes memory) {
(bytes32 key, bytes memory value) = map._inner._at(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);
}

Expand All @@ -203,8 +207,9 @@ library EnumerableMapAddresses {
* @return bool indicating whether the key was in the map
* @return bytes The value associated with the key
*/
function _tryGet(AddressToBytesMap storage map, address key) internal view returns (bool, bytes memory) {
return map._inner._tryGet(bytes32(uint256(uint160(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))));
}

/**
Expand All @@ -215,6 +220,6 @@ library EnumerableMapAddresses {
*/
// 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))));
return map._inner.get(bytes32(uint256(uint160(key))));
}
}
136 changes: 136 additions & 0 deletions contracts/src/v0.8/shared/enumerable/EnumerableMapBytes32.sol
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit bd1e9a6

Please sign in to comment.