88 lines
3.2 KiB
Solidity
88 lines
3.2 KiB
Solidity
// SPDX-License-Identifier: AGPL-3.0-only
|
|
pragma solidity ^0.8.0;
|
|
|
|
import "../interfaces/AddressWhitelistInterface.sol";
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
import "./Lockable.sol";
|
|
|
|
/**
|
|
* @title A contract to track a whitelist of addresses.
|
|
*/
|
|
contract AddressWhitelist is AddressWhitelistInterface, Ownable, Lockable {
|
|
enum Status { None, In, Out }
|
|
mapping(address => Status) public whitelist;
|
|
|
|
address[] public whitelistIndices;
|
|
|
|
event AddedToWhitelist(address indexed addedAddress);
|
|
event RemovedFromWhitelist(address indexed removedAddress);
|
|
|
|
/**
|
|
* @notice Adds an address to the whitelist.
|
|
* @param newElement the new address to add.
|
|
*/
|
|
function addToWhitelist(address newElement) external override nonReentrant() onlyOwner {
|
|
// Ignore if address is already included
|
|
if (whitelist[newElement] == Status.In) {
|
|
return;
|
|
}
|
|
|
|
// Only append new addresses to the array, never a duplicate
|
|
if (whitelist[newElement] == Status.None) {
|
|
whitelistIndices.push(newElement);
|
|
}
|
|
|
|
whitelist[newElement] = Status.In;
|
|
|
|
emit AddedToWhitelist(newElement);
|
|
}
|
|
|
|
/**
|
|
* @notice Removes an address from the whitelist.
|
|
* @param elementToRemove the existing address to remove.
|
|
*/
|
|
function removeFromWhitelist(address elementToRemove) external override nonReentrant() onlyOwner {
|
|
if (whitelist[elementToRemove] != Status.Out) {
|
|
whitelist[elementToRemove] = Status.Out;
|
|
emit RemovedFromWhitelist(elementToRemove);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Checks whether an address is on the whitelist.
|
|
* @param elementToCheck the address to check.
|
|
* @return True if `elementToCheck` is on the whitelist, or False.
|
|
*/
|
|
function isOnWhitelist(address elementToCheck) external view override nonReentrantView() returns (bool) {
|
|
return whitelist[elementToCheck] == Status.In;
|
|
}
|
|
|
|
/**
|
|
* @notice Gets all addresses that are currently included in the whitelist.
|
|
* @dev Note: This method skips over, but still iterates through addresses. It is possible for this call to run out
|
|
* of gas if a large number of addresses have been removed. To reduce the likelihood of this unlikely scenario, we
|
|
* can modify the implementation so that when addresses are removed, the last addresses in the array is moved to
|
|
* the empty index.
|
|
* @return activeWhitelist the list of addresses on the whitelist.
|
|
*/
|
|
function getWhitelist() external view override nonReentrantView() returns (address[] memory activeWhitelist) {
|
|
// Determine size of whitelist first
|
|
uint256 activeCount = 0;
|
|
for (uint256 i = 0; i < whitelistIndices.length; i++) {
|
|
if (whitelist[whitelistIndices[i]] == Status.In) {
|
|
activeCount++;
|
|
}
|
|
}
|
|
|
|
// Populate whitelist
|
|
activeWhitelist = new address[](activeCount);
|
|
activeCount = 0;
|
|
for (uint256 i = 0; i < whitelistIndices.length; i++) {
|
|
address addr = whitelistIndices[i];
|
|
if (whitelist[addr] == Status.In) {
|
|
activeWhitelist[activeCount] = addr;
|
|
activeCount++;
|
|
}
|
|
}
|
|
}
|
|
} |