-
Notifications
You must be signed in to change notification settings - Fork 83
/
ERC1155Ubiquity.sol
316 lines (287 loc) · 9.89 KB
/
ERC1155Ubiquity.sol
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol";
import {ERC1155BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155BurnableUpgradeable.sol";
import {ERC1155PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../interfaces/IAccessControl.sol";
import "../libraries/Constants.sol";
import "../../../src/dollar/utils/SafeAddArray.sol";
/**
* @notice ERC1155 Ubiquity preset
* @notice ERC1155 with:
* - ERC1155 minter, burner and pauser
* - TotalSupply per id
* - Ubiquity Manager access control
*/
contract ERC1155Ubiquity is
Initializable,
ERC1155BurnableUpgradeable,
ERC1155PausableUpgradeable,
UUPSUpgradeable
{
using SafeAddArray for uint256[];
/// @notice Access control interface
IAccessControl public accessControl;
/// @notice Mapping from account to array of token ids held by the account
mapping(address => uint256[]) public holderBalances;
/// @notice Total supply among all token ids
uint256 public totalSupply;
// ----------- Modifiers -----------
/// @notice Modifier checks that the method is called by a user with the "Governance minter" role
modifier onlyMinter() virtual {
require(
accessControl.hasRole(GOVERNANCE_TOKEN_MINTER_ROLE, _msgSender()),
"ERC1155Ubiquity: not minter"
);
_;
}
/// @notice Modifier checks that the method is called by a user with the "Governance burner" role
modifier onlyBurner() virtual {
require(
accessControl.hasRole(GOVERNANCE_TOKEN_BURNER_ROLE, _msgSender()),
"ERC1155Ubiquity: not burner"
);
_;
}
/// @notice Modifier checks that the method is called by a user with the "Pauser" role
modifier onlyPauser() virtual {
require(
accessControl.hasRole(PAUSER_ROLE, _msgSender()),
"ERC1155Ubiquity: not pauser"
);
_;
}
/// @notice Modifier checks that the method is called by a user with the "Admin" role
modifier onlyAdmin() {
require(
accessControl.hasRole(DEFAULT_ADMIN_ROLE, _msgSender()),
"ERC20Ubiquity: not admin"
);
_;
}
/// @notice Ensures __ERC1155Ubiquity_init cannot be called on the implementation contract
constructor() {
_disableInitializers();
}
/// @notice Initializes this contract with all base(parent) contracts
/// @param _manager Address of the manager of the contract
/// @param _uri Base URI
function __ERC1155Ubiquity_init(
address _manager,
string memory _uri
) public initializer onlyInitializing {
// init base contracts
__ERC1155_init(_uri);
__ERC1155Burnable_init();
__ERC1155Pausable_init();
__UUPSUpgradeable_init();
// init current contract
__ERC1155Ubiquity_init_unchained(_manager);
}
/// @notice Initializes the current contract
/// @param _manager Address of the manager of the contract
function __ERC1155Ubiquity_init_unchained(
address _manager
) public initializer onlyInitializing {
accessControl = IAccessControl(_manager);
}
/**
* @notice Returns access control address
* @return Access control address
*/
function getManager() external view returns (address) {
return address(accessControl);
}
/**
* @notice Sets access control address
* @param _manager New access control address
*/
function setManager(address _manager) external onlyAdmin {
accessControl = IAccessControl(_manager);
}
/**
* @notice Sets base URI
* @param newURI New URI
*/
function setUri(string memory newURI) external onlyAdmin {
_setURI(newURI);
}
/**
* @notice Creates `amount` new tokens for `to`, of token type `id`
* @param to Address where to mint tokens
* @param id Token type id
* @param amount Tokens amount to mint
* @param data Arbitrary data
*/
function mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual onlyMinter {
_mint(to, id, amount, data);
totalSupply += amount;
holderBalances[to].add(id);
}
/**
* @notice Mints multiple token types for `to` address
* @param to Address where to mint tokens
* @param ids Array of token type ids
* @param amounts Array of token amounts
* @param data Arbitrary data
*/
function mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual onlyMinter whenNotPaused {
_mintBatch(to, ids, amounts, data);
uint256 localTotalSupply = totalSupply;
for (uint256 i = 0; i < ids.length; ++i) {
localTotalSupply += amounts[i];
}
totalSupply = localTotalSupply;
holderBalances[to].add(ids);
}
/// @notice Pauses all token transfers
function pause() public virtual onlyPauser {
_pause();
}
/// @notice Unpauses all token transfers
function unpause() public virtual onlyPauser {
_unpause();
}
/**
* @notice Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a `TransferSingle` event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via `setApprovalForAll`.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement `IERC1155Receiver-onERC1155Received` and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
super.safeTransferFrom(from, to, id, amount, data);
holderBalances[to].add(id);
}
/**
* @notice Batched version of `safeTransferFrom()`
*
* Emits a `TransferBatch` event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement `IERC1155Receiver-onERC1155BatchReceived` and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
super.safeBatchTransferFrom(from, to, ids, amounts, data);
holderBalances[to].add(ids);
}
/**
* @notice Returns array of token ids held by the `holder`
* @param holder Account to check tokens for
* @return Array of tokens which `holder` has
*/
function holderTokens(
address holder
) public view returns (uint256[] memory) {
return holderBalances[holder];
}
/**
* @notice Destroys `amount` tokens of token type `id` from `account`
*
* Emits a `TransferSingle` event.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens of token type `id`.
*/
function _burn(
address account,
uint256 id,
uint256 amount
) internal virtual override whenNotPaused {
super._burn(account, id, amount);
totalSupply -= amount;
}
/**
* @notice Batched version of `_burn()`
*
* Emits a `TransferBatch` event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/
function _burnBatch(
address account,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual override whenNotPaused {
super._burnBatch(account, ids, amounts);
for (uint256 i = 0; i < ids.length; ++i) {
totalSupply -= amounts[i];
}
}
/**
* @notice Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
)
internal
virtual
override(ERC1155PausableUpgradeable, ERC1155Upgradeable)
{
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
}
/// @notice Allows an admin to upgrade to another implementation contract
/// @param newImplementation Address of the new implementation contract
function _authorizeUpgrade(
address newImplementation
) internal virtual override onlyAdmin {}
/// @notice Allows for future upgrades on the base contract without affecting the storage of the derived contract
uint256[50] private __gap;
}