Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BytesSet #2395

Merged
merged 6 commits into from
Nov 4, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* `Address`: added `functionStaticCall` and `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333))
* `TimelockController`: added a contract to augment access control schemes with a delay. ([#2364](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2364))
* `EnumerableSet`: added `BytesSet`, for sets of `bytes32`. ([#2395](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2395))

## 3.2.0 (2020-09-10)

Expand Down
33 changes: 32 additions & 1 deletion contracts/mocks/EnumerableSetMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,37 @@ pragma solidity ^0.6.0;

import "../utils/EnumerableSet.sol";

// Bytes32Set
contract EnumerableBytes32SetMock {
using EnumerableSet for EnumerableSet.Bytes32Set;

event OperationResult(bool result);

EnumerableSet.Bytes32Set private _set;

function contains(bytes32 value) public view returns (bool) {
return _set.contains(value);
}

function add(bytes32 value) public {
bool result = _set.add(value);
emit OperationResult(result);
}

function remove(bytes32 value) public {
bool result = _set.remove(value);
emit OperationResult(result);
}

function length() public view returns (uint256) {
return _set.length();
}

function at(uint256 index) public view returns (bytes32) {
return _set.at(index);
}
}

// AddressSet
contract EnumerableAddressSetMock {
using EnumerableSet for EnumerableSet.AddressSet;
Expand Down Expand Up @@ -64,4 +95,4 @@ contract EnumerableUintSetMock {
function at(uint256 index) public view returns (uint256) {
return _set.at(index);
}
}
}
58 changes: 56 additions & 2 deletions contracts/utils/EnumerableSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ pragma solidity ^0.6.0;
* }
* ```
*
* As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
* (`UintSet`) are supported.
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
Expand Down Expand Up @@ -132,6 +132,60 @@ library EnumerableSet {
return set._values[index];
}

// 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);
}

// AddressSet

struct AddressSet {
Expand Down
16 changes: 15 additions & 1 deletion test/utils/EnumerableSet.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
const { BN } = require('@openzeppelin/test-helpers');

const EnumerableBytes32SetMock = artifacts.require('EnumerableBytes32SetMock');
const EnumerableAddressSetMock = artifacts.require('EnumerableAddressSetMock');
const EnumerableUintSetMock = artifacts.require('EnumerableUintSetMock');

const { shouldBehaveLikeSet } = require('./EnumerableSet.behavior');

contract('EnumerableSet', function (accounts) {
// Bytes32Set
describe('EnumerableBytes32Set', function () {
const bytesA = '0xdeadbeef'.padEnd(66, '0');
const bytesB = '0x0123456789'.padEnd(66, '0');
const bytesC = '0x42424242'.padEnd(66, '0');

beforeEach(async function () {
this.set = await EnumerableBytes32SetMock.new();
});

shouldBehaveLikeSet(bytesA, bytesB, bytesC);
});

// AddressSet
describe('EnumerableAddressSet', function () {
const [ accountA, accountB, accountC ] = accounts;
const [accountA, accountB, accountC] = accounts;

beforeEach(async function () {
this.set = await EnumerableAddressSetMock.new();
Expand Down