eth-accounts-index

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

AccountsIndex.sol (4512B)


      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 writers;
     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 		writers[_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 writers[_writer];
     52 		emit WriterDeleted(_writer);
     53 		return true;
     54 	}
     55 
     56 	// Implements Writer
     57 	function isWriter(address _writer) public view returns (bool) {
     58 		return writers[_writer] || _writer == owner;
     59 	}
     60 
     61 	// Implements AccountsIndex
     62 	function add(address _account) external returns (bool) {
     63 		uint256 i;
     64 		uint256 _entry;
     65 
     66 		require(isWriter(msg.sender));
     67 		require(entryIndex[_account] == 0);
     68 		require(entryList.length < (1 << 64));
     69 		i = entryList.length;
     70 		entryList.push(_account);
     71 		_entry = uint64(i);
     72 		_entry |= block.timestamp << 64;
     73 		entryIndex[_account] = _entry;
     74 		emit AddressAdded(_account);
     75 		return true;
     76 	}
     77 
     78 	// Implements AccountsIndexMutable
     79 	function remove(address _account) external returns (bool) {
     80 		uint256 i;
     81 		uint256 l;
     82 
     83 		require(isWriter(msg.sender), 'ERR_AXX');
     84 		require(this.have(_account), 'ERR_ACL');
     85 
     86 		l = entryList.length - 1;
     87 
     88 		i = entryIndex[_account];
     89 		if (i < l) {
     90 			entryList[i] = entryList[l];
     91 		}		
     92 		entryList.pop();
     93 		entryIndex[_account] = 0;
     94 		emit AddressRemoved(_account);
     95 		return true;
     96 	}
     97 
     98 	// Implements AccountsIndexMutable
     99 	function activate(address _account) external returns (bool) {
    100 		require(isWriter(msg.sender), 'ERR_AXX');
    101 		require(entryIndex[_account] > 0, 'ERR_NOT_FOUND');
    102 	        require(entryIndex[_account] & blockedField == blockedField, 'ERR_NOT_BLOCKED');
    103 		entryIndex[_account] >>= 129;
    104 		emit AddressActive(_account, true);
    105 		return true;
    106 	}
    107 
    108 	// Implements AccountsIndexMutable
    109 	function deactivate(address _account) external returns (bool) {
    110 		require(isWriter(msg.sender));
    111 		require(entryIndex[_account] > 0, 'ERR_NOT_FOUND');
    112 		require(entryIndex[_account] & blockedField == 0, 'ERR_NOT_ACTIVE');
    113 		entryIndex[_account] <<= 129;
    114 		entryIndex[_account] |= blockedField;
    115 		emit AddressActive(_account, false);
    116 		return true;
    117 	}
    118 
    119 	// Implements AccountsIndex
    120 	function entry(uint256 _i) external view returns (address) {
    121 		return entryList[_i + 1];
    122 	}
    123 
    124 	// Implements AccountsIndex
    125 	function time(address _account) external view returns (uint256) {
    126 		require(entryIndex[_account] > 0);
    127 		return entryIndex[_account] >> 64;
    128 	}
    129 
    130 
    131 	// Implements AccountsIndex
    132 	function have(address _account) external view returns (bool) {
    133 		return entryIndex[_account] > 0;
    134 	}
    135 
    136 	// Implements AccountsIndexMutable
    137 	function isActive(address _account) external view returns (bool) {
    138 		return this.have(_account) && entryIndex[_account] & blockedField != blockedField;
    139 	}
    140 
    141 	// Implements EIP173
    142 	function transferOwnership(address _newOwner) public returns (bool) {
    143 		address oldOwner;
    144 		require(msg.sender == owner, 'ERR_AXX');
    145 
    146 		oldOwner = owner;
    147 		owner = _newOwner;
    148 
    149 		emit OwnershipTransferred(oldOwner, owner);
    150 		return true;
    151 	}
    152 
    153 	// Implements EIP165
    154 	function supportsInterface(bytes4 _sum) public pure returns (bool) {
    155 		if (_sum == 0xb7bca625) { // AccountsIndex
    156 			return true;
    157 		}
    158 		if (_sum == 0x9479f0ae) { // AccountsIndexMutable
    159 			return true;
    160 		}
    161 		if (_sum == 0x01ffc9a7) { // EIP165
    162 			return true;
    163 		}
    164 		if (_sum == 0x9493f8b2) { // EIP173
    165 			return true;
    166 		}
    167 		if (_sum == 0xabe1f1f5) { // Writer
    168 			return true;
    169 		}
    170 		return false;
    171 	}
    172 }