accounts-index

Accounts index evm contract tooling with permissioned writes
Log | Files | Refs

AccountsIndex.sol (4377B)


      1 pragma solidity >=0.8.0;
      2 
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 // File-Version: 3
      5 
      6 contract AccountsIndex {
      7 	uint256 constant blockedField = 1 << 128;
      8 	address[] entryList;
      9 	mapping(address => uint256) entryIndex;
     10 
     11 	// Implements Writer
     12 	mapping(address => bool) public isWriter;
     13 
     14 	// Implements ERC173
     15 	address public owner;
     16 
     17 	// Implements AccountsIndex
     18 	event AddressAdded(address _account); // AccountsIndex
     19 	// Implements AccountsIndexMutable
     20 	event AddressActive(address indexed _account, bool _active);
     21 	// Implements AccountsIndexMutable
     22 	event AddressRemoved(address _account);
     23 	// Implements ERC173
     24 	event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); // EIP173
     25 	// Implements Writer
     26 	event WriterAdded(address _account); // AccountsIndex
     27 	// Implements Writer
     28 	event WriterDeleted(address _account);
     29 
     30 	constructor() {
     31 		owner = msg.sender;
     32 		entryList.push(address(0));
     33 	}
     34 
     35 	// Implements AccountsIndex
     36 	function entryCount() external view returns (uint256) {
     37 		return entryList.length - 1;
     38 	}
     39 
     40 	// Implements Writer
     41 	function addWriter(address _writer) public returns (bool) {
     42 		require(owner == msg.sender, 'ERR_AXX');
     43 		isWriter[_writer] = true;
     44 		emit WriterAdded(_writer);
     45 		return true;
     46 	}
     47 
     48 	// Implements Writer
     49 	function deleteWriter(address _writer) public returns (bool) {
     50 		require(owner == msg.sender, 'ERR_AXX');
     51 		delete isWriter[_writer];
     52 		emit WriterDeleted(_writer);
     53 		return true;
     54 	}
     55 
     56 	// Implements AccountsIndex
     57 	function add(address _account) external returns (bool) {
     58 		uint256 i;
     59 		uint256 _entry;
     60 
     61 		require(isWriter[msg.sender]);
     62 		require(entryIndex[_account] == 0);
     63 		require(entryList.length < (1 << 64));
     64 		i = entryList.length;
     65 		entryList.push(_account);
     66 		_entry = uint64(i);
     67 		_entry |= block.timestamp << 64;
     68 		entryIndex[_account] = _entry;
     69 		emit AddressAdded(_account);
     70 		return true;
     71 	}
     72 
     73 	// Implements AccountsIndexMutable
     74 	function remove(address _account) external returns (bool) {
     75 		uint256 i;
     76 		uint256 l;
     77 
     78 		require(isWriter[msg.sender], 'ERR_AXX');
     79 		require(this.have(_account), 'ERR_ACL');
     80 
     81 		l = entryList.length - 1;
     82 
     83 		i = entryIndex[_account];
     84 		if (i < l) {
     85 			entryList[i] = entryList[l];
     86 		}		
     87 		entryList.pop();
     88 		entryIndex[_account] = 0;
     89 		emit AddressRemoved(_account);
     90 		return true;
     91 	}
     92 
     93 	// Implements AccountsIndexMutable
     94 	function activate(address _account) external returns (bool) {
     95 		require(isWriter[msg.sender], 'ERR_AXX');
     96 		require(entryIndex[_account] > 0, 'ERR_NOT_FOUND');
     97 	        require(entryIndex[_account] & blockedField == blockedField, 'ERR_NOT_BLOCKED');
     98 		entryIndex[_account] >>= 129;
     99 		emit AddressActive(_account, true);
    100 		return true;
    101 	}
    102 
    103 	// Implements AccountsIndexMutable
    104 	function deactivate(address _account) external returns (bool) {
    105 		require(isWriter[msg.sender]);
    106 		require(entryIndex[_account] > 0, 'ERR_NOT_FOUND');
    107 		require(entryIndex[_account] & blockedField == 0, 'ERR_NOT_ACTIVE');
    108 		entryIndex[_account] <<= 129;
    109 		entryIndex[_account] |= blockedField;
    110 		emit AddressActive(_account, false);
    111 		return true;
    112 	}
    113 
    114 	// Implements AccountsIndex
    115 	function entry(uint256 _i) external view returns (address) {
    116 		return entryList[_i + 1];
    117 	}
    118 
    119 	// Implements AccountsIndex
    120 	function time(address _account) external view returns (uint256) {
    121 		require(entryIndex[_account] > 0);
    122 		return entryIndex[_account] >> 64;
    123 	}
    124 
    125 
    126 	// Implements AccountsIndex
    127 	function have(address _account) external view returns (bool) {
    128 		return entryIndex[_account] > 0;
    129 	}
    130 
    131 	// Implements AccountsIndexMutable
    132 	function isActive(address _account) external view returns (bool) {
    133 		return this.have(_account) && entryIndex[_account] & blockedField != blockedField;
    134 	}
    135 
    136 	// Implements EIP173
    137 	function transferOwnership(address _newOwner) public returns (bool) {
    138 		address oldOwner;
    139 		require(msg.sender == owner, 'ERR_AXX');
    140 
    141 		oldOwner = owner;
    142 		owner = _newOwner;
    143 
    144 		emit OwnershipTransferred(oldOwner, owner);
    145 		return true;
    146 	}
    147 
    148 	// Implements EIP165
    149 	function supportsInterface(bytes4 _sum) public pure returns (bool) {
    150 		if (_sum == 0xb7bca625) { // AccountsIndex
    151 			return true;
    152 		}
    153 		if (_sum == 0x9479f0ae) { // AccountsIndexMutable
    154 			return true;
    155 		}
    156 		if (_sum == 0x01ffc9a7) { // EIP165
    157 			return true;
    158 		}
    159 		if (_sum == 0x9493f8b2) { // EIP173
    160 			return true;
    161 		}
    162 		if (_sum == 0xabe1f1f5) { // Writer
    163 			return true;
    164 		}
    165 		return false;
    166 	}
    167 }