forked from AmazingAng/WTF-Solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathERC1155.sol
319 lines (284 loc) · 10.7 KB
/
ERC1155.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
317
318
319
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./IERC1155MetadataURI.sol";
import "../34_ERC721/Address.sol";
import "../34_ERC721/String.sol";
import "../34_ERC721/IERC165.sol";
/**
* @dev ERC1155多代币标准
* 见 https://eips.ethereum.org/EIPS/eip-1155
*/
contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI {
using Address for address; // 使用Address库,用isContract来判断地址是否为合约
using Strings for uint256; // 使用String库
// Token名称
string public name;
// Token代号
string public symbol;
// 代币种类id 到 账户account 到 余额balances 的映射
mapping(uint256 => mapping(address => uint256)) private _balances;
// 发起方地址address 到 授权地址operator 到 是否授权bool 的批量授权映射
mapping(address => mapping(address => bool)) private _operatorApprovals;
/**
* 构造函数,初始化`name` 和`symbol`, uri_
*/
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
interfaceId == type(IERC165).interfaceId;
}
/**
* @dev 持仓查询 实现IERC1155的balanceOf,返回account地址的id种类代币持仓量。
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
/**
* @dev 批量持仓查询
* 要求:
* - `accounts` 和 `ids` 数组长度相等.
*/
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public view virtual override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev 批量授权,调用者授权operator使用其所有代币
* 释放{ApprovalForAll}事件
* 条件:msg.sender != operator
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
require(msg.sender != operator, "ERC1155: setting approval status for self");
_operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
/**
* @dev 查询批量授权.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev 安全转账,将`amount`单位的`id`种类代币从`from`转账到`to`
* 释放 {TransferSingle} 事件.
* 要求:
* - to 不能是0地址.
* - from拥有足够的持仓量,且调用者拥有授权
* - 如果 to 是智能合约, 他必须支持 IERC1155Receiver-onERC1155Received.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
address operator = msg.sender;
// 调用者是持有者或是被授权
require(
from == operator || isApprovedForAll(from, operator),
"ERC1155: caller is not token owner nor approved"
);
require(to != address(0), "ERC1155: transfer to the zero address");
// from地址有足够持仓
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
// 更新持仓量
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
// 释放事件
emit TransferSingle(operator, from, to, id, amount);
// 安全检查
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev 批量安全转账,将`amounts`数组单位的`ids`数组种类代币从`from`转账到`to`
* 释放 {TransferSingle} 事件.
* 要求:
* - to 不能是0地址.
* - from拥有足够的持仓量,且调用者拥有授权
* - 如果 to 是智能合约, 他必须支持 IERC1155Receiver-onERC1155BatchReceived.
* - ids和amounts数组长度相等
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
address operator = msg.sender;
// 调用者是持有者或是被授权
require(
from == operator || isApprovedForAll(from, operator),
"ERC1155: caller is not token owner nor approved"
);
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
// 通过for循环更新持仓
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
// 安全检查
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev 铸造
* 释放 {TransferSingle} 事件.
*/
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = msg.sender;
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
/**
* @dev 批量铸造
* 释放 {TransferBatch} 事件.
*/
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = msg.sender;
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev 销毁
*/
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = msg.sender;
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
}
/**
* @dev 批量销毁
*/
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = msg.sender;
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
}
// @dev ERC1155的安全转账检查
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
// @dev ERC1155的批量安全转账检查
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non-ERC1155Receiver implementer");
}
}
}
/**
* @dev 返回ERC1155的id种类代币的uri,存储metadata,类似ERC721的tokenURI.
*/
function uri(uint256 id) public view virtual override returns (string memory) {
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, id.toString())) : "";
}
/**
* 计算{uri}的BaseURI,uri就是把baseURI和tokenId拼接在一起,需要开发重写.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
}