Skip to content

Commit 48d09ce

Browse files
committed
Nonfungible ERC1155 implementation
1 parent 6383299 commit 48d09ce

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.20;
4+
5+
import {ERC1155} from "../ERC1155.sol";
6+
import {Arrays} from "../../../utils/Arrays.sol";
7+
8+
/**
9+
* @dev Indicates that the operator is trying to mint a token that already exists.
10+
* @param id Identifier of token being minted
11+
* @param owner Current token owner
12+
*/
13+
error ERC1155NonfungibleDuplicate(uint256 id, address owner);
14+
15+
/**
16+
* @dev Indicates that the operator is trying mint/transfer/burn an amount > 1 of a token
17+
*/
18+
error ERC1155NonfungibleInvalidAmount(uint256 id, uint256 amount);
19+
20+
/**
21+
* @dev For tokens that are nonfungible but prefer to use {ERC1155} rather than {ERC721}.
22+
*
23+
* {ERC1155Nonfungible} takes advantage of nonfungibility constraint to replace data model
24+
* tracking multiple account balances per token with with a more gas-efficient data model
25+
* tracking unique ownership per token.
26+
*
27+
* Moreover {ERC1155Nonfungible} makes it possible to query the owner of a specific token via {ERC1155Nonfungible-ownerOf},
28+
* similar to {ERC721-ownerOf}, but differs from {ERC721-ownerOf} in that querying the owner of an inexistent token
29+
* will not revert but will return `address(0)`.
30+
*/
31+
abstract contract ERC1155Nonfungible is ERC1155 {
32+
using Arrays for uint256[];
33+
using Arrays for address[];
34+
35+
mapping(uint256 id => address) private _owners;
36+
37+
/**
38+
* @dev Returns the owner of the token `id`. Does NOT revert if token doesn't exist.
39+
*
40+
* {ERC1155Nonfungible-ownerOf} and {ERC1155Nonfungible-_setOwnerOf} may be overridden in tandem,
41+
* e.g. to store more token information along with the owner
42+
*/
43+
function ownerOf(uint256 id) public view virtual returns (address) {
44+
return _owners[id];
45+
}
46+
47+
/**
48+
* @dev {ERC1155Nonfungible-ownerOf} and {ERC1155Nonfungible-_setOwnerOf} may be overridden in tandem,
49+
* e.g. to store more token information along with the owner
50+
*/
51+
function _setOwnerOf(uint256 id, address owner) internal virtual {
52+
_owners[id] = owner;
53+
}
54+
55+
/**
56+
* @dev Replaces {ERC1155-balanceOf} implementation entirely.
57+
*/
58+
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
59+
return account != address(0) && ownerOf(id) == account ? 1 : 0;
60+
}
61+
62+
/**
63+
* @dev Replaces {ERC1155-_update} implementation entirely.
64+
*/
65+
function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual override {
66+
if (ids.length != values.length) {
67+
revert ERC1155InvalidArrayLength(ids.length, values.length);
68+
}
69+
70+
address operator = _msgSender();
71+
72+
for (uint256 i = 0; i < ids.length; ++i) {
73+
uint256 id = ids.unsafeMemoryAccess(i);
74+
uint256 value = values.unsafeMemoryAccess(i);
75+
76+
if (value == 1) {
77+
address currOwner = ownerOf(id);
78+
// Could be written more compactly, but clearer if mint tackled separately from transfer/burn
79+
if (from == address(0)) {
80+
if (currOwner == address(0)) {
81+
_setOwnerOf(id, to);
82+
} else {
83+
revert ERC1155NonfungibleDuplicate(id, currOwner);
84+
}
85+
} else {
86+
if (from == currOwner) {
87+
_setOwnerOf(id, to);
88+
} else {
89+
revert ERC1155InsufficientBalance({ sender: from, balance: 0, needed: 1, tokenId: id });
90+
}
91+
}
92+
} else if (value == 0) {
93+
// ERC-1155 allows zero-value transfers
94+
} else {
95+
revert ERC1155NonfungibleInvalidAmount(id, value);
96+
}
97+
}
98+
99+
if (ids.length == 1) {
100+
uint256 id = ids.unsafeMemoryAccess(0);
101+
uint256 value = values.unsafeMemoryAccess(0);
102+
emit TransferSingle(operator, from, to, id, value);
103+
} else {
104+
emit TransferBatch(operator, from, to, ids, values);
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)