pragma solidity >=0.8.0; // SPDX-License-Identifier: AGPL-3.0-or-later // File-Version: 3 contract AccountsIndex { uint256 constant blockedField = 1 << 128; address[] entryList; mapping(address => uint256) entryIndex; // Implements Writer mapping(address => bool) public isWriter; // Implements ERC173 address public owner; // Implements AccountsIndex event AddressAdded(address _account); // AccountsIndex // Implements AccountsIndexMutable event AddressActive(address indexed _account, bool _active); // Implements AccountsIndexMutable event AddressRemoved(address _account); // Implements ERC173 event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173 // Implements Writer event WriterAdded(address _account); // AccountsIndex // Implements Writer event WriterDeleted(address _account); constructor() { owner = msg.sender; entryList.push(address(0)); } // Implements AccountsIndex function entryCount() external view returns (uint256) { return entryList.length - 1; } // Implements Writer function addWriter(address _writer) public returns (bool) { require(owner == msg.sender, 'ERR_AXX'); isWriter[_writer] = true; emit WriterAdded(_writer); return true; } // Implements Writer function deleteWriter(address _writer) public returns (bool) { require(owner == msg.sender, 'ERR_AXX'); delete isWriter[_writer]; emit WriterDeleted(_writer); return true; } // Implements AccountsIndex function add(address _account) external returns (bool) { uint256 i; uint256 _entry; require(isWriter[msg.sender]); require(entryIndex[_account] == 0); require(entryList.length < (1 << 64)); i = entryList.length; entryList.push(_account); _entry = uint64(i); _entry |= block.timestamp << 64; entryIndex[_account] = _entry; emit AddressAdded(_account); return true; } // Implements AccountsIndexMutable function remove(address _account) external returns (bool) { uint256 i; uint256 l; require(isWriter[msg.sender], 'ERR_AXX'); require(this.have(_account), 'ERR_ACL'); l = entryList.length - 1; i = entryIndex[_account]; if (i < l) { entryList[i] = entryList[l]; } entryList.pop(); entryIndex[_account] = 0; emit AddressRemoved(_account); return true; } // Implements AccountsIndexMutable function activate(address _account) external returns (bool) { require(isWriter[msg.sender], 'ERR_AXX'); require(entryIndex[_account] > 0, 'ERR_NOT_FOUND'); require(entryIndex[_account] & blockedField == blockedField, 'ERR_NOT_BLOCKED'); entryIndex[_account] >>= 129; emit AddressActive(_account, true); return true; } // Implements AccountsIndexMutable function deactivate(address _account) external returns (bool) { require(isWriter[msg.sender]); require(entryIndex[_account] > 0, 'ERR_NOT_FOUND'); require(entryIndex[_account] & blockedField == 0, 'ERR_NOT_ACTIVE'); entryIndex[_account] <<= 129; entryIndex[_account] |= blockedField; emit AddressActive(_account, false); return true; } // Implements AccountsIndex function entry(uint256 _i) external view returns (address) { return entryList[_i + 1]; } // Implements AccountsIndex function time(address _account) external view returns (uint256) { require(entryIndex[_account] > 0); return entryIndex[_account] >> 64; } // Implements AccountsIndex function have(address _account) external view returns (bool) { return entryIndex[_account] > 0; } // Implements AccountsIndexMutable function isActive(address _account) external view returns (bool) { return this.have(_account) && entryIndex[_account] & blockedField != blockedField; } // Implements EIP173 function transferOwnership(address _newOwner) public returns (bool) { address oldOwner; require(msg.sender == owner, 'ERR_AXX'); oldOwner = owner; owner = _newOwner; emit OwnershipTransferred(oldOwner, owner); return true; } // Implements EIP165 function supportsInterface(bytes4 _sum) public pure returns (bool) { if (_sum == 0xb7bca625) { // AccountsIndex return true; } if (_sum == 0x9479f0ae) { // AccountsIndexMutable return true; } if (_sum == 0x01ffc9a7) { // EIP165 return true; } if (_sum == 0x9493f8b2) { // EIP173 return true; } if (_sum == 0xabe1f1f5) { // Writer return true; } return false; } }