欢迎订阅专栏 :3分钟Solidity--智能合约--Web3区块链技术必学
如需获取本内容的最新版本,请参见 Cyfrin.io 上的ERC1155(代码示例)
与 ERC-20 和其他标准相比,ERC-1155 代币协议标准突出的地方在于它是如何跨链兼容的。到目前为止,用户的大部分资产只能在以太坊区块链上使用,然而 ERC-1155 标准也使其资产与其他生态系统兼容,能够跨多个区块链进行操作似乎是唯一的出路。
ERC-1155 与传统的代币非常不同,不能直接销毁。 相反,除非最初的开发人员定期买回代币,否则它们通常仍在流通。ERC-1155 的定位为更具体的代币标准,因为在此标准上任何资产都可以在任何给定时间创建和销毁。
ERC1155 示例
scss
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
interface IERC1155 {
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 value,
bytes calldata data
) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external;
function balanceOf(address owner, uint256 id)
external
view
returns (uint256);
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
external
view
returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address owner, address operator)
external
view
returns (bool);
}
interface IERC1155TokenReceiver {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
contract ERC1155 is IERC1155 {
event TransferSingle(
address indexed operator,
address indexed from,
address indexed to,
uint256 id,
uint256 value
);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
event ApprovalForAll(
address indexed owner, address indexed operator, bool approved
);
event URI(string value, uint256 indexed id);
// owner => id => balance
mapping(address => mapping(uint256 => uint256)) public balanceOf;
// owner => operator => approved
mapping(address => mapping(address => bool)) public isApprovedForAll;
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
external
view
returns (uint256[] memory balances)
{
require(owners.length == ids.length, "owners length != ids length");
balances = new uint256[](owners.length);
unchecked {
for (uint256 i = 0; i < owners.length; i++) {
balances[i] = balanceOf[owners[i]][ids[i]];
}
}
}
function setApprovalForAll(address operator, bool approved) external {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 value,
bytes calldata data
) external {
require(
msg.sender == from || isApprovedForAll[from][msg.sender],
"not approved"
);
require(to != address(0), "to = 0 address");
balanceOf[from][id] -= value;
balanceOf[to][id] += value;
emit TransferSingle(msg.sender, from, to, id, value);
if (to.code.length > 0) {
require(
IERC1155TokenReceiver(to).onERC1155Received(
msg.sender, from, id, value, data
) == IERC1155TokenReceiver.onERC1155Received.selector,
"unsafe transfer"
);
}
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external {
require(
msg.sender == from || isApprovedForAll[from][msg.sender],
"not approved"
);
require(to != address(0), "to = 0 address");
require(ids.length == values.length, "ids length != values length");
for (uint256 i = 0; i < ids.length; i++) {
balanceOf[from][ids[i]] -= values[i];
balanceOf[to][ids[i]] += values[i];
}
emit TransferBatch(msg.sender, from, to, ids, values);
if (to.code.length > 0) {
require(
IERC1155TokenReceiver(to).onERC1155BatchReceived(
msg.sender, from, ids, values, data
) == IERC1155TokenReceiver.onERC1155BatchReceived.selector,
"unsafe transfer"
);
}
}
// ERC165
function supportsInterface(bytes4 interfaceId)
external
pure
returns (bool)
{
return interfaceId == 0x01ffc9a7 // ERC165 Interface ID for ERC165
|| interfaceId == 0xd9b67a26 // ERC165 Interface ID for ERC1155
|| interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
}
// ERC1155 Metadata URI
function uri(uint256 id) public view virtual returns (string memory) {}
// Internal functions
function _mint(address to, uint256 id, uint256 value, bytes memory data)
internal
{
require(to != address(0), "to = 0 address");
balanceOf[to][id] += value;
emit TransferSingle(msg.sender, address(0), to, id, value);
if (to.code.length > 0) {
require(
IERC1155TokenReceiver(to).onERC1155Received(
msg.sender, address(0), id, value, data
) == IERC1155TokenReceiver.onERC1155Received.selector,
"unsafe transfer"
);
}
}
function _batchMint(
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) internal {
require(to != address(0), "to = 0 address");
require(ids.length == values.length, "ids length != values length");
for (uint256 i = 0; i < ids.length; i++) {
balanceOf[to][ids[i]] += values[i];
}
emit TransferBatch(msg.sender, address(0), to, ids, values);
if (to.code.length > 0) {
require(
IERC1155TokenReceiver(to).onERC1155BatchReceived(
msg.sender, address(0), ids, values, data
) == IERC1155TokenReceiver.onERC1155BatchReceived.selector,
"unsafe transfer"
);
}
}
function _burn(address from, uint256 id, uint256 value) internal {
require(from != address(0), "from = 0 address");
balanceOf[from][id] -= value;
emit TransferSingle(msg.sender, from, address(0), id, value);
}
function _batchBurn(
address from,
uint256[] calldata ids,
uint256[] calldata values
) internal {
require(from != address(0), "from = 0 address");
require(ids.length == values.length, "ids length != values length");
for (uint256 i = 0; i < ids.length; i++) {
balanceOf[from][ids[i]] -= values[i];
}
emit TransferBatch(msg.sender, from, address(0), ids, values);
}
}
contract MyMultiToken is ERC1155 {
function mint(uint256 id, uint256 value, bytes memory data) external {
_mint(msg.sender, id, value, data);
}
function batchMint(
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external {
_batchMint(msg.sender, ids, values, data);
}
function burn(uint256 id, uint256 value) external {
_burn(msg.sender, id, value);
}
function batchBurn(uint256[] calldata ids, uint256[] calldata values)
external
{
_batchBurn(msg.sender, ids, values);
}
}
Remix Lite 尝试一下