OpenZeppelin / OpenZeppelin/openzeppelin-contracts

Enable setting and getting multiple bits in `Bitmaps.sol`

Open
#3,963 25 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Solidity
Stars
27.2k
Forks
12.4k
Avg merge
2d 19h
Merged PRs (30d)
33

Description

🧐 Motivation

  • The Bitmaps library can be greatly expanded in its usefulness if setting and getting multiple bits is enabled

This would be helpful, e.g., in an NFT bitmap-based airdrop where we start with 1-bits and switch them to 0 as mints occur.
This would also be helpful in the case where a protocol is using bitpacking (e.g., this is directly useful in Panoptic), as in: https://twitter.com/cryptojesperk/status/1613207330782416897?s=20&t=dDcU6hQPJEGzoo8sX8PJ8A

📝 Details
These new functions are added via function overloading (the argument list is changed from taking an index to a startIndex and num):

  • set(BitMap storage bitmap, uint256 startIndex, uint256 num)
  • get(BitMap storage bitmap, uint256 startIndex, uint256 num)
  • setTo(BitMap storage bitmap, uint256 startIndex, uint256 num, bool value)
  • unset(BitMap storage bitmap, uint256 startIndex, uint256 num)

Where "startIndex" is the starting index of the first bit to interact with. "num" is the number of bits to interact with (set or unset) from the startIndex onwards.

Consider the following 256 bits (32 bytes, or 1 word) example:

exampleBitmap = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Currently, we can set or unset 1 bit at a time. With these new functions, we can set n bits at once.

For example:

exampleBitmap = exampleBitmap.set(5, 10);

sets the bits starting at index 5 to 15 to 1 - and leaves the rest at 0 - in a single function call:

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111110000

And we can get those bits back:

exampleBitmap = exampleBitmap.get(5, 10);

Returns the bits:

1111111111

The bits can be returned in various formats to be decided. Potentially as an array of uint256s. An event would be emitted also detailing the start index and the number of bits that are returned.

The difficult parts will be when bits are set across overlapping _data elements, but can be handled, among other complex situations (which can all be handled).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing Bitmaps.sol and its existing single-bit operations. Clarify the return representation and boundary behavior for ranges crossing _data elements, then define tests covering setting, getting, and unsetting ranges; the work is done when the overloaded APIs and their edge cases are specified and covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
solidity
Domain
blockchain
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.