-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathGenericRegistry.sol
More file actions
142 lines (125 loc) · 6.02 KB
/
Copy pathGenericRegistry.sol
File metadata and controls
142 lines (125 loc) · 6.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "../lib/solmate/src/tokens/ERC721.sol";
import "./interfaces/IErrorsRegistries.sol";
/// @title Generic Registry - Smart contract for generic registry template
/// @author Aleksandr Kuperman - <aleksandr.kuperman@valory.xyz>
abstract contract GenericRegistry is IErrorsRegistries, ERC721 {
event OwnerUpdated(address indexed owner);
event ManagerUpdated(address indexed manager);
event BaseURIChanged(string baseURI);
// Owner address
address public owner;
// Unit manager
address public manager;
// Base URI
string public baseURI;
// Unit counter
uint256 public totalSupply;
// Reentrancy lock
uint256 internal _locked = 1;
// To better understand the CID anatomy, please refer to: https://proto.school/anatomy-of-a-cid/05
// CID = <multibase_encoding>multibase_encoding(<cid-version><multicodec><multihash-algorithm><multihash-length><multihash-hash>)
// CID prefix = <multibase_encoding>multibase_encoding(<cid-version><multicodec><multihash-algorithm><multihash-length>)
// to complement the multibase_encoding(<multihash-hash>)
// multibase_encoding = base16 = "f"
// cid-version = version 1 = "0x01"
// multicodec = dag-pb = "0x70"
// multihash-algorithm = sha2-256 = "0x12"
// multihash-length = 256 bits = "0x20"
string public constant CID_PREFIX = "f01701220";
/// @dev Changes the owner address.
/// @param newOwner Address of a new owner.
function changeOwner(address newOwner) external virtual {
// Check for the ownership
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}
// Check for the zero address
if (newOwner == address(0)) {
revert ZeroAddress();
}
owner = newOwner;
emit OwnerUpdated(newOwner);
}
/// @dev Changes the unit manager.
/// @param newManager Address of a new unit manager.
function changeManager(address newManager) external virtual {
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}
// Check for the zero address
if (newManager == address(0)) {
revert ZeroAddress();
}
manager = newManager;
emit ManagerUpdated(newManager);
}
/// @dev Checks for the unit existence.
/// @notice Unit counter starts from 1.
/// @param unitId Unit Id.
/// @return true if the unit exists, false otherwise.
function exists(uint256 unitId) external view virtual returns (bool) {
return unitId > 0 && unitId < (totalSupply + 1);
}
/// @dev Sets unit base URI.
/// @param bURI Base URI string.
function setBaseURI(string memory bURI) external virtual {
// Check for the ownership
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}
// Check for the zero value
if (bytes(bURI).length == 0) {
revert ZeroValue();
}
baseURI = bURI;
emit BaseURIChanged(bURI);
}
/// @dev Gets the valid unit Id from the provided index.
/// @notice Unit counter starts from 1.
/// @param id Unit counter.
/// @return unitId Unit Id.
function tokenByIndex(uint256 id) external view virtual returns (uint256 unitId) {
unitId = id + 1;
if (unitId > totalSupply) {
revert Overflow(unitId, totalSupply);
}
}
// Open sourced from: https://stackoverflow.com/questions/67893318/solidity-how-to-represent-bytes32-as-string
/// @dev Converts bytes16 input data to hex16.
/// @notice This method converts bytes into the same bytes-character hex16 representation.
/// @param data bytes16 input data.
/// @return result hex16 conversion from the input bytes16 data.
function _toHex16(bytes16 data) internal pure returns (bytes32 result) {
result = bytes32 (data) & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 |
(bytes32 (data) & 0x0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000) >> 64;
result = result & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 |
(result & 0x00000000FFFFFFFF000000000000000000000000FFFFFFFF0000000000000000) >> 32;
result = result & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 |
(result & 0x0000FFFF000000000000FFFF000000000000FFFF000000000000FFFF00000000) >> 16;
result = result & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 |
(result & 0x00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000) >> 8;
result = (result & 0xF000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000) >> 4 |
(result & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) >> 8;
result = bytes32 (0x3030303030303030303030303030303030303030303030303030303030303030 +
uint256 (result) +
(uint256 (result) + 0x0606060606060606060606060606060606060606060606060606060606060606 >> 4 &
0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F) * 39);
}
/// @dev Gets the hash of the unit.
/// @param unitId Unit Id.
/// @return Unit hash.
function _getUnitHash(uint256 unitId) internal view virtual returns (bytes32);
/// @dev Returns unit token URI.
/// @notice Expected multicodec: dag-pb; hashing function: sha2-256, with base16 encoding and leading CID_PREFIX removed.
/// @param unitId Unit Id.
/// @return Unit token URI string.
function tokenURI(uint256 unitId) public view virtual override returns (string memory) {
bytes32 unitHash = _getUnitHash(unitId);
// Parse 2 parts of bytes32 into left and right hex16 representation, and concatenate into string
// adding the base URI and a cid prefix for the full base16 multibase prefix IPFS hash representation
return string(abi.encodePacked(baseURI, CID_PREFIX, _toHex16(bytes16(unitHash)),
_toHex16(bytes16(unitHash << 128))));
}
}