-
Notifications
You must be signed in to change notification settings - Fork 261
Expand file tree
/
Copy pathSlotsBitmapLibrary.sol
More file actions
116 lines (109 loc) · 3.75 KB
/
SlotsBitmapLibrary.sol
File metadata and controls
116 lines (109 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.23;
import {ISuperfluidToken} from "../interfaces/superfluid/ISuperfluidToken.sol";
/**
* @title Slots Bitmap library
* @author Superfluid
* @dev A library implements slots bitmap on Superfluid Token storage
* NOTE:
* - A slots bitmap allows you to iterate through a list of data efficiently.
* - A data slot can be enabled or disabled with the help of bitmap.
* - MAX_NUM_SLOTS is 256 in this implementation (using one uint256)
* - Superfluid token storage usage:
* - updateAgreementStateSlot(bitmapStateSlotId) stores the bitmap of enabled data slots
* - updateAgreementStateSlot(dataStateSlotIDStart + stotId) stores the data of the slot
*/
library SlotsBitmapLibrary {
uint32 internal constant _MAX_NUM_SLOTS = 256;
function findEmptySlotAndFill(
ISuperfluidToken token,
address account,
uint256 bitmapStateSlotId,
uint256 dataStateSlotIDStart,
bytes32 data
)
public
returns (uint32 slotId)
{
uint256 subsBitmap = uint256(token.getAgreementStateSlot(
address(this),
account,
bitmapStateSlotId, 1)[0]);
for (slotId = 0; slotId < _MAX_NUM_SLOTS; ++slotId) {
if ((uint256(subsBitmap >> slotId) & 1) == 0) {
// update slot data
bytes32[] memory slotData = new bytes32[](1);
slotData[0] = data;
token.updateAgreementStateSlot(
account,
dataStateSlotIDStart + slotId,
slotData);
// update slot map
slotData[0] = bytes32(subsBitmap | (1 << uint256(slotId)));
token.updateAgreementStateSlot(
account,
bitmapStateSlotId,
slotData);
// update the slots
break;
}
}
require(slotId < _MAX_NUM_SLOTS, "SlotBitmap out of bound");
}
function clearSlot(
ISuperfluidToken token,
address account,
uint256 bitmapStateSlotId,
uint32 slotId
)
public
{
uint256 subsBitmap = uint256(token.getAgreementStateSlot(
address(this),
account,
bitmapStateSlotId, 1)[0]);
bytes32[] memory slotData = new bytes32[](1);
// [SECURITY] NOTE: We do not allow clearing of nonexistent slots
assert(subsBitmap & (1 << uint256(slotId)) != 0);
slotData[0] = bytes32(subsBitmap & ~(1 << uint256(slotId)));
// zero the data
token.updateAgreementStateSlot(
account,
bitmapStateSlotId,
slotData);
}
function listData(
ISuperfluidToken token,
address account,
uint256 bitmapStateSlotId,
uint256 dataStateSlotIDStart
)
public view
returns (
uint32[] memory slotIds,
bytes32[] memory dataList)
{
uint256 subsBitmap = uint256(token.getAgreementStateSlot(
address(this),
account,
bitmapStateSlotId, 1)[0]);
slotIds = new uint32[](_MAX_NUM_SLOTS);
dataList = new bytes32[](_MAX_NUM_SLOTS);
// read all slots
uint nSlots;
for (uint32 slotId = 0; slotId < _MAX_NUM_SLOTS; ++slotId) {
if ((uint256(subsBitmap >> slotId) & 1) == 0) continue;
slotIds[nSlots] = slotId;
dataList[nSlots] = token.getAgreementStateSlot(
address(this),
account,
dataStateSlotIDStart + slotId, 1)[0];
++nSlots;
}
// resize memory arrays
assembly {
mstore(slotIds, nSlots)
mstore(dataList, nSlots)
}
}
}