parent
94697be8a3
commit
954ebe66c3
@ -0,0 +1,112 @@ |
||||
// SPDX-License-Identifier: MIT |
||||
|
||||
pragma solidity ^0.8.20; |
||||
|
||||
import {ERC1155} from "../ERC1155.sol"; |
||||
import {Arrays} from "../../../utils/Arrays.sol"; |
||||
|
||||
/** |
||||
* @dev Indicates that the operator is trying to mint a token that already exists. |
||||
* @param id Identifier of token being minted |
||||
* @param owner Current token owner |
||||
*/ |
||||
error ERC1155NonfungibleDuplicate(uint256 id, address owner); |
||||
|
||||
/** |
||||
* @dev Indicates that the operator is trying mint/transfer/burn an amount > 1 of a token |
||||
*/ |
||||
error ERC1155NonfungibleInvalidAmount(uint256 id, uint256 amount); |
||||
|
||||
/** |
||||
* @dev For tokens that are nonfungible but prefer to use {ERC1155} rather than {ERC721}. |
||||
* |
||||
* {ERC1155Nonfungible} takes advantage of nonfungibility constraint to replace data model |
||||
* tracking multiple account balances per token with with a more gas-efficient data model |
||||
* tracking unique ownership per token. |
||||
* |
||||
* Moreover {ERC1155Nonfungible} makes it possible to query the owner of a specific token via {ERC1155Nonfungible-ownerOf}, |
||||
* similar to {ERC721-ownerOf}, but differs from {ERC721-ownerOf} in that querying the owner of an inexistent token |
||||
* will not revert but will return `address(0)`. |
||||
*/ |
||||
abstract contract ERC1155Nonfungible is ERC1155 { |
||||
using Arrays for uint256[]; |
||||
using Arrays for address[]; |
||||
|
||||
mapping(uint256 id => address) private _owners; |
||||
|
||||
/** |
||||
* @dev Returns the owner of the token `id`. Does NOT revert if token doesn't exist. |
||||
* |
||||
* {ERC1155Nonfungible-ownerOf} and {ERC1155Nonfungible-_setOwnerOf} may be overridden in tandem, |
||||
* e.g. to store more token information along with the owner |
||||
*/ |
||||
function ownerOf(uint256 id) public view virtual returns (address) { |
||||
return _owners[id]; |
||||
} |
||||
|
||||
/** |
||||
* @dev {ERC1155Nonfungible-ownerOf} and {ERC1155Nonfungible-_setOwnerOf} may be overridden in tandem, |
||||
* e.g. to store more token information along with the owner |
||||
*/ |
||||
function _setOwnerOf(uint256 id, address owner) internal virtual { |
||||
_owners[id] = owner; |
||||
} |
||||
|
||||
/** |
||||
* @dev Replaces {ERC1155-balanceOf} implementation entirely. |
||||
*/ |
||||
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { |
||||
return account != address(0) && ownerOf(id) == account ? 1 : 0; |
||||
} |
||||
|
||||
/** |
||||
* @dev Replaces {ERC1155-_update} implementation entirely. |
||||
*/ |
||||
function _update( |
||||
address from, |
||||
address to, |
||||
uint256[] memory ids, |
||||
uint256[] memory values |
||||
) internal virtual override { |
||||
if (ids.length != values.length) { |
||||
revert ERC1155InvalidArrayLength(ids.length, values.length); |
||||
} |
||||
|
||||
address operator = _msgSender(); |
||||
|
||||
for (uint256 i = 0; i < ids.length; ++i) { |
||||
uint256 id = ids.unsafeMemoryAccess(i); |
||||
uint256 value = values.unsafeMemoryAccess(i); |
||||
|
||||
if (value == 1) { |
||||
address currOwner = ownerOf(id); |
||||
// Could be written more compactly, but clearer if mint tackled separately from transfer/burn |
||||
if (from == address(0)) { |
||||
if (currOwner == address(0)) { |
||||
_setOwnerOf(id, to); |
||||
} else { |
||||
revert ERC1155NonfungibleDuplicate(id, currOwner); |
||||
} |
||||
} else { |
||||
if (from == currOwner) { |
||||
_setOwnerOf(id, to); |
||||
} else { |
||||
revert ERC1155InsufficientBalance({sender: from, balance: 0, needed: 1, tokenId: id}); |
||||
} |
||||
} |
||||
} else if (value == 0) { |
||||
// ERC-1155 allows zero-value transfers |
||||
} else { |
||||
revert ERC1155NonfungibleInvalidAmount(id, value); |
||||
} |
||||
} |
||||
|
||||
if (ids.length == 1) { |
||||
uint256 id = ids.unsafeMemoryAccess(0); |
||||
uint256 value = values.unsafeMemoryAccess(0); |
||||
emit TransferSingle(operator, from, to, id, value); |
||||
} else { |
||||
emit TransferBatch(operator, from, to, ids, values); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue