Skip to content

Commit 0461ee2

Browse files
committed
feat: add ERC1155 Data and Metadata facets and module
1 parent ee63ccb commit 0461ee2

3 files changed

Lines changed: 238 additions & 0 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.30;
3+
4+
/* Compose
5+
* https://compose.diamonds
6+
*/
7+
8+
/**
9+
* @title ERC-1155 Multi Token Standard
10+
*
11+
*/
12+
contract ERC1155DataFacet {
13+
/**
14+
* @notice Error indicating array length mismatch in batch operations.
15+
* @param _idsLength Length of the ids array.
16+
* @param _valuesLength Length of the values array.
17+
*/
18+
error ERC1155InvalidArrayLength(uint256 _idsLength, uint256 _valuesLength);
19+
20+
/**
21+
* @dev Storage position determined by the keccak256 hash of the diamond storage identifier.
22+
*/
23+
bytes32 constant STORAGE_POSITION = keccak256("erc1155");
24+
25+
/**
26+
* @dev ERC-8042 compliant storage struct for ERC-1155 token data.
27+
* @custom:storage-location erc8042:erc1155
28+
*/
29+
struct ERC1155Storage {
30+
mapping(uint256 id => mapping(address account => uint256 balance)) balanceOf;
31+
mapping(address account => mapping(address operator => bool)) isApprovedForAll;
32+
string uri;
33+
string baseURI;
34+
mapping(uint256 tokenId => string) tokenURIs;
35+
}
36+
37+
/**
38+
* @notice Returns the ERC-1155 storage struct from the predefined diamond storage slot.
39+
* @dev Uses inline assembly to set the storage slot reference.
40+
* @return s The ERC-1155 storage struct reference.
41+
*/
42+
function getStorage() internal pure returns (ERC1155Storage storage s) {
43+
bytes32 position = STORAGE_POSITION;
44+
assembly {
45+
s.slot := position
46+
}
47+
}
48+
49+
/**
50+
* @notice Returns the amount of tokens of token type `id` owned by `account`.
51+
* @param _account The address to query the balance of.
52+
* @param _id The token type to query.
53+
* @return The balance of the token type.
54+
*/
55+
function balanceOf(address _account, uint256 _id) external view returns (uint256) {
56+
return getStorage().balanceOf[_id][_account];
57+
}
58+
59+
/**
60+
* @notice Batched version of {balanceOf}.
61+
* @param _accounts The addresses to query the balances of.
62+
* @param _ids The token types to query.
63+
* @return balances The balances of the token types.
64+
*/
65+
function balanceOfBatch(address[] calldata _accounts, uint256[] calldata _ids)
66+
external
67+
view
68+
returns (uint256[] memory balances)
69+
{
70+
if (_accounts.length != _ids.length) {
71+
revert ERC1155InvalidArrayLength(_ids.length, _accounts.length);
72+
}
73+
74+
ERC1155Storage storage s = getStorage();
75+
balances = new uint256[](_accounts.length);
76+
77+
for (uint256 i = 0; i < _accounts.length; i++) {
78+
balances[i] = s.balanceOf[_ids[i]][_accounts[i]];
79+
}
80+
}
81+
82+
/**
83+
* @notice Returns true if `operator` is approved to transfer `account`'s tokens.
84+
* @param _account The token owner.
85+
* @param _operator The operator to query.
86+
* @return True if the operator is approved, false otherwise.
87+
*/
88+
function isApprovedForAll(address _account, address _operator) external view returns (bool) {
89+
return getStorage().isApprovedForAll[_account][_operator];
90+
}
91+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.30;
3+
4+
/* Compose
5+
* https://compose.diamonds
6+
*/
7+
8+
/**
9+
* @title ERC-1155 Metadata Facet
10+
* @notice Provides URI metadata functionality for ERC-1155 tokens.
11+
*/
12+
contract ERC1155MetadataFacet {
13+
/**
14+
* @notice Emitted when the URI for token type `_id` changes to `_value`.
15+
* @param _value The new URI for the token type.
16+
* @param _id The token type whose URI changed.
17+
*/
18+
event URI(string _value, uint256 indexed _id);
19+
20+
/**
21+
* @dev Storage position determined by the keccak256 hash of the diamond storage identifier.
22+
*/
23+
bytes32 constant STORAGE_POSITION = keccak256("erc1155");
24+
25+
/**
26+
* @dev ERC-8042 compliant storage struct for ERC-1155 token data.
27+
* @custom:storage-location erc8042:erc1155
28+
*/
29+
struct ERC1155Storage {
30+
mapping(uint256 id => mapping(address account => uint256 balance)) balanceOf;
31+
mapping(address account => mapping(address operator => bool)) isApprovedForAll;
32+
string uri;
33+
string baseURI;
34+
mapping(uint256 tokenId => string) tokenURIs;
35+
}
36+
37+
/**
38+
* @notice Returns the ERC-1155 storage struct from the predefined diamond storage slot.
39+
* @dev Uses inline assembly to set the storage slot reference.
40+
* @return s The ERC-1155 storage struct reference.
41+
*/
42+
function getStorage() internal pure returns (ERC1155Storage storage s) {
43+
bytes32 position = STORAGE_POSITION;
44+
assembly {
45+
s.slot := position
46+
}
47+
}
48+
49+
/**
50+
* @notice Returns the URI for token type `_id`.
51+
* @dev If a token-specific URI is set in tokenURIs[_id], returns the concatenation of baseURI and tokenURIs[_id].
52+
* Note that baseURI is empty by default and must be set explicitly if concatenation is desired.
53+
* If no token-specific URI is set, returns the default URI which applies to all token types.
54+
* The default URI may contain the substring `{id}` which clients should replace with the actual token ID.
55+
* @param _id The token ID to query.
56+
* @return The URI for the token type.
57+
*/
58+
function uri(uint256 _id) external view returns (string memory) {
59+
ERC1155Storage storage s = getStorage();
60+
string memory tokenURI = s.tokenURIs[_id];
61+
62+
return bytes(tokenURI).length > 0 ? string.concat(s.baseURI, tokenURI) : s.uri;
63+
}
64+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.30;
3+
4+
/* Compose
5+
* https://compose.diamonds
6+
*/
7+
8+
/**
9+
* @title ERC-1155 Metadata Module
10+
* @notice Provides internal metadata functionality for ERC-1155 tokens.
11+
*/
12+
13+
/**
14+
* @notice Emitted when the URI for token type `_id` changes to `_value`.
15+
* @param _value The new URI for the token type.
16+
* @param _id The token type whose URI changed.
17+
*/
18+
event URI(string _value, uint256 indexed _id);
19+
20+
/**
21+
* @dev Storage position determined by the keccak256 hash of the diamond storage identifier.
22+
*/
23+
bytes32 constant STORAGE_POSITION = keccak256("erc1155");
24+
25+
/**
26+
* @dev ERC-8042 compliant storage struct for ERC-1155 token data.
27+
* @custom:storage-location erc8042:erc1155
28+
*/
29+
struct ERC1155Storage {
30+
mapping(uint256 id => mapping(address account => uint256 balance)) balanceOf;
31+
mapping(address account => mapping(address operator => bool)) isApprovedForAll;
32+
string uri;
33+
string baseURI;
34+
mapping(uint256 tokenId => string) tokenURIs;
35+
}
36+
37+
/**
38+
* @notice Returns the ERC-1155 storage struct from the predefined diamond storage slot.
39+
* @dev Uses inline assembly to set the storage slot reference.
40+
* @return s The ERC-1155 storage struct reference.
41+
*/
42+
function getStorage() pure returns (ERC1155Storage storage s) {
43+
bytes32 position = STORAGE_POSITION;
44+
assembly {
45+
s.slot := position
46+
}
47+
}
48+
49+
/**
50+
* @notice Sets the token-specific URI for a given token ID.
51+
* @dev Sets tokenURIs[_tokenId] to the provided string and emits a URI event with the full computed URI.
52+
* The emitted URI is the concatenation of baseURI and the token-specific URI.
53+
* @param _tokenId The token ID to set the URI for.
54+
* @param _tokenURI The token-specific URI string to be concatenated with baseURI.
55+
*/
56+
function setTokenURI(uint256 _tokenId, string memory _tokenURI) {
57+
ERC1155Storage storage s = getStorage();
58+
s.tokenURIs[_tokenId] = _tokenURI;
59+
60+
string memory fullURI = bytes(_tokenURI).length > 0 ? string.concat(s.baseURI, _tokenURI) : s.uri;
61+
emit URI(fullURI, _tokenId);
62+
}
63+
64+
/**
65+
* @notice Sets the base URI prefix for token-specific URIs.
66+
* @dev The base URI is concatenated with token-specific URIs set via setTokenURI.
67+
* Does not affect the default URI used when no token-specific URI is set.
68+
* @param _baseURI The base URI string to prepend to token-specific URIs.
69+
*/
70+
function setBaseURI(string memory _baseURI) {
71+
ERC1155Storage storage s = getStorage();
72+
s.baseURI = _baseURI;
73+
}
74+
75+
/**
76+
* @notice Sets the default URI for all token types.
77+
* @dev This URI is used when no token-specific URI is set.
78+
* @param _uri The default URI string.
79+
*/
80+
function setURI(string memory _uri) {
81+
ERC1155Storage storage s = getStorage();
82+
s.uri = _uri;
83+
}

0 commit comments

Comments
 (0)