TokenUniqueSymbolIndex.sol (4795B)
1 pragma solidity >=0.8.0; 2 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 5 contract TokenUniqueSymbolIndex { 6 mapping(address => bool) isWriter; 7 mapping ( bytes32 => uint256 ) registry; 8 mapping ( address => bytes32 ) tokenIndex; 9 address[] tokens; 10 11 // Implements EIP173 12 address public owner; 13 14 // Implements Registry 15 bytes32[] public identifierList; 16 17 // Implements EIP173 18 event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 19 20 // Implements AccountsIndex 21 event AddressKey(bytes32 indexed _symbol, address _token); 22 23 // Implements AccountsIndex 24 event AddressAdded(address _token); 25 26 // Implements AccountsIndexMutable 27 event AddressRemoved(address _token); 28 29 // Implements Writer 30 event WriterAdded(address _writer); 31 32 // Implements Writer 33 event WriterDeleted(address _writer); 34 35 constructor() { 36 owner = msg.sender; 37 tokens.push(address(0)); 38 identifierList.push(bytes32(0)); 39 } 40 41 // Implements AccountsIndex 42 function entry(uint256 _idx) public view returns ( address ) { 43 return tokens[_idx + 1]; 44 } 45 46 // Implements RegistryClient 47 function addressOf(bytes32 _key) public view returns ( address ) { 48 uint256 idx; 49 50 idx = registry[_key]; 51 return tokens[idx]; 52 } 53 54 // Attempt to register the token at the given address. 55 // Will revet if symbol cannot be retrieved, or if symbol already exists. 56 function register(address _token) public returns (bool) { 57 require(isWriter[msg.sender]); 58 59 bytes memory token_symbol; 60 bytes32 token_symbol_key; 61 uint256 idx; 62 63 (bool _ok, bytes memory _r) = _token.call(abi.encodeWithSignature('symbol()')); 64 require(_ok); 65 66 token_symbol = abi.decode(_r, (bytes)); 67 require(token_symbol.length <= 32, 'ERR_TOKEN_SYMBOL_TOO_LONG'); 68 token_symbol_key = bytes32(token_symbol); 69 70 idx = registry[token_symbol_key]; 71 require(idx == 0); 72 73 registry[token_symbol_key] = tokens.length; 74 tokens.push(_token); 75 identifierList.push(token_symbol_key); 76 tokenIndex[_token] = token_symbol_key; 77 78 emit AddressKey(token_symbol_key, _token); 79 emit AddressAdded(_token); 80 return true; 81 } 82 83 // Implements AccountsIndex 84 function add(address _token) public returns (bool) { 85 return register(_token); 86 } 87 88 // Implements AccountsIndex 89 function time(address _token) public pure returns(uint256) { 90 _token; 91 return 0; 92 } 93 94 // Implements AccountsIndexMutable 95 function remove(address _token) external returns (bool) { 96 uint256 i; 97 uint256 l; 98 99 require(isWriter[msg.sender] || msg.sender == owner, 'ERR_AXX'); 100 require(tokenIndex[_token] != bytes32(0), 'ERR_NOT_FOUND'); 101 102 l = tokens.length - 1; 103 i = registry[tokenIndex[_token]]; 104 if (i < l) { 105 tokens[i] = tokens[l]; 106 identifierList[i] = identifierList[l]; 107 } 108 registry[tokenIndex[tokens[i]]] = i; 109 tokens.pop(); 110 identifierList.pop(); 111 registry[tokenIndex[_token]] = 0; 112 tokenIndex[_token] = bytes32(0); 113 114 emit AddressRemoved(_token); 115 return true; 116 } 117 118 // Implements AccountsIndexMutable 119 function activate(address _token) public pure returns(bool) { 120 _token; 121 return false; 122 } 123 124 // Implements AccountsIndexMutable 125 function deactivate(address _token) public pure returns(bool) { 126 _token; 127 return false; 128 } 129 130 131 // Implements AccountsIndex 132 function entryCount() public view returns ( uint256 ) { 133 return tokens.length - 1; 134 } 135 136 // Implements EIP173 137 function transferOwnership(address _newOwner) public returns (bool) { 138 address oldOwner; 139 140 require(msg.sender == owner); 141 oldOwner = owner; 142 owner = _newOwner; 143 144 emit OwnershipTransferred(oldOwner, owner); 145 146 return true; 147 } 148 149 // Implements Writer 150 function addWriter(address _writer) public returns (bool) { 151 require(owner == msg.sender); 152 isWriter[_writer] = true; 153 154 emit WriterAdded(_writer); 155 156 return true; 157 } 158 159 // Implements Writer 160 function deleteWriter(address _writer) public returns (bool) { 161 require(owner == msg.sender); 162 delete isWriter[_writer]; 163 164 emit WriterDeleted(_writer); 165 166 return true; 167 } 168 169 // Implements Registry 170 function identifier(uint256 _idx) public view returns(bytes32) { 171 return identifierList[_idx + 1]; 172 } 173 174 // Implements Registry 175 function identifierCount() public view returns(uint256) { 176 return identifierList.length - 1; 177 } 178 179 // Implements AccountsIndex 180 function have(address _token) public view returns(bool) { 181 return tokenIndex[_token] != bytes32(0x0); 182 } 183 184 // Implements EIP165 185 function supportsInterface(bytes4 _sum) public pure returns (bool) { 186 if (_sum == 0xeffbf671) { // Registry 187 return true; 188 } 189 if (_sum == 0xb7bca625) { // AccountsIndex 190 return true; 191 } 192 if (_sum == 0x9479f0ae) { // AccountsIndexMutable 193 return true; 194 } 195 if (_sum == 0x01ffc9a7) { // EIP165 196 return true; 197 } 198 if (_sum == 0x9493f8b2) { // EIP173 199 return true; 200 } 201 if (_sum == 0x80c84bd6) { // Writer 202 return true; 203 } 204 return false; 205 } 206 }