ERC1155结合了ERC20和ERC721的能力,这是一个标准接口,支持开发同质化的、半同质化的、非同质化的代币和其他配置的通用智能合约。
ERC1155结合了ERC20和ERC721的能力,这是一个标准接口,支持开发同质化的、半同质化的、非同质化的代币和其他配置的通用智能合约。
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
// IERC1155接口同样继承了IERC165接口
interface IERC1155 is IERC165 {
// 转移代币后触发事件,记录转移信息
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
);
// 授权approve后触发事件,记录授权信息
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
// URI的值改变时触发该事件,记录信息
event URI(string value, uint256 indexed id);
// 获取account账户对应代币id拥有的数量
function balanceOf(address account, uint256 id) external view returns (uint256);
// 获取账户列表对用的token余额,相当于多次balanceOf
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
// 设置给operate的授权
function setApprovalForAll(address operator, bool approved) external;
// 判断operate是否有account账号的授权
function isApprovedForAll(address account, address operator) external view returns (bool);
// 从from账户转移amount数量的代币id到to地址
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
// 批量转移token,相当于调用多次safeTransfer
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
// 代币id与拥有者地址及其该代币余额的映射
mapping(uint256 => mapping(address => uint256)) private _balances;
// 地址之间的授权状态的映射
mapping(address => mapping(address => bool)) private _operatorApprovals;
// 相同类型的代币 _uri是一致的
string private _uri;
// 构造函数 初始化uri
constructor(string memory uri_) {
_setURI(uri_);
}
// 检查合约是否实现该接口
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
// 获取代币的uri,uri指向是代币的元数据,例如图片信息
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
// 获取account地址的id代币的数量
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
// 检查account不为空地址
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
// 返回account账号列表对应的id代币的数量
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
// 检查账号列表长度与代币id列表长度一致
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
// 创建一个列表长度与account相同
uint256[] memory batchBalances = new uint256[](accounts.length);
// 获取账号对应的代币id的数量
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
// 设置对operate的授权approve状态
function setApprovalForAll(address operator, bool approved) public virtual override {
// 调用_setApprovalForAll函数
_setApprovalForAll(_msgSender(), operator, approved);
}
// 获取account地址对operate地址的授权状态
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
// 转移mount数量的id代币 从from地址到to地址
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
// 检查from是否是合约调用者地址,或者from账号有approve授权给合约调用者
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
// 调用_safeTransferFrom函数,转移代币
_safeTransferFrom(from, to, id, amount, data);
}
// 批量转移代币
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
// 检查from是否是合约调用者地址,或者from账号有approve授权给合约调用者
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner or approved"
);
// 调用_safeBatchTransferFrom函数转移代币
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
// 转移mount数量的id代币 从from地址到to地址
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
// 检查to地址是否为空地址
require(to != address(0), "ERC1155: transfer to the zero address");
// 获取当前合约调用者地址
address operator = _msgSender();
// 获取id列表,该列表只有一个元素 ids[0] = id
uint256[] memory ids = _asSingletonArray(id);
// 获取amount列表该列表只有一个元素 amounts[0] = amount
uint256[] memory amounts = _asSingletonArray(amount);
// 转移代币前执行的函数
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
// 获取from地址的id代币数量
uint256 fromBalance = _balances[id][from];
// 检查 from地址的id代币数量fromBalance 是否大于等于要转移的数量amount
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);
// 代币转移后执行函数
_afterTokenTransfer(operator, from, to, ids, amounts, data);
// 检查接收的合约地址是否实现IERC1155Receiver接口
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
// 检查账号列表长度与代币id列表长度一致
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
// 检查to地址是否为空地址
require(to != address(0), "ERC1155: transfer to the zero address");
// 获取当前合约调用者地址
address operator = _msgSender();
// 代币转移前执行函数
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
// 获取代币id
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);
// 代币转移后执行函数
_afterTokenTransfer(operator, from, to, ids, amounts, data);
// 检查接收的合约地址是否实现IERC1155Receiver接口
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
// 设置新uri地址
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
// 铸造amount数量id代币给to地址
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
// 检查to是否是空地址
require(to != address(0), "ERC1155: mint to the zero address");
// 获取合约调用者地址
address operator = _msgSender();
// 获取id列表,该列表只有一个元素 ids[0] = id
uint256[] memory ids = _asSingletonArray(id);
// 获取amount列表该列表只有一个元素 amounts[0] = amount
uint256[] memory amounts = _asSingletonArray(amount);
// 代币转移前执行函数
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
// 增加代币余额
_balances[id][to] += amount;
// 触发转移单个代币事件,记录信息
emit TransferSingle(operator, address(0), to, id, amount);
// 代币转移后执行函数
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
// 检查接收的合约地址是否实现IERC1155Receiver接口
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
// 铸造amounts列表对应ids列表代币给to地址
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
// 检查to是否是空地址
require(to != address(0), "ERC1155: mint to the zero address");
// 检查账号列表长度与代币id列表长度一致
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
// 获取当前合约调用者地址
address operator = _msgSender();
// 代币转移前执行函数
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
// 增加代币余额
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
// 触发转移单个代币事件,记录信息
emit TransferBatch(operator, address(0), to, ids, amounts);
// 代币转移后执行函数
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
// 检查接收的合约地址是否实现IERC1155Receiver接口
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
//销毁from地址的id代币
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
// 检查from地址 不为空地址
require(from != address(0), "ERC1155: burn from the zero address");
// 获取当前合约调用者地址
address operator = _msgSender();
// 获取id列表,该列表只有一个元素 ids[0] = id
uint256[] memory ids = _asSingletonArray(id);
// 获取amount列表该列表只有一个元素 amounts[0] = amount
uint256[] memory amounts = _asSingletonArray(amount);
// 代币转移前执行函数
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
// 获取from账号id代币余额
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);
// 代币转移后执行函数
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
// 批量销毁地址拥有的各种id代币
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
// 检查from地址 不为空地址
require(from != address(0), "ERC1155: burn from the zero address");
// 检查账号列表长度与代币id列表长度一致
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
// 获取当前合约调用者地址
address operator = _msgSender();
// 代币转移前执行函数
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
// 销毁代币
for (uint256 i = 0; i < ids.length; i++) {
// 获取代币id
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);
// 代币转移后执行函数
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
// 设置owner对operate的授权状态
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
// 检查 owner地址和operate地址是否相同
require(owner != operator, "ERC1155: setting approval status for self");
// 设置对operate的授权approve状态
_operatorApprovals[owner][operator] = approved;
// 触发授权事件
emit ApprovalForAll(owner, operator, approved);
}
// 代币转移前函数
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
// 代币转移后执行函数
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
// 如果to是普通地址则返回ture,如果to是合约地址则检查该合约是否实现onERC1155Received接口
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");
}
}
}
// 如果to是普通地址则返回ture,如果to是合约地址则检查该合约是否实现onERC1155Received接口
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");
}
}
}
// 返回包含单个元素的列表
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!