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 "https://github.com/AmazingAng/WTF-Solidity/blob/main/34_ERC721/Address.sol"; import "https://github.com/AmazingAng/WTF-Solidity/blob/main/34_ERC721/String.sol"; import "https://github.com/AmazingAng/WTF-Solidity/blob/main/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; // 使用Strings库 // Token名称 string public name; // Token代号 string public symbol; // 代币种类id 到 账户account 到 余额balances 的映射 mapping(uint256 => mapping(address => uint256)) private _balances; // address 到 授权地址 的批量授权映射 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 ""; } }
|