diff --git a/contracts/token/ERC1155/ERC1155.sol b/contracts/token/ERC1155/ERC1155.sol index 2e39cbb423b..609cb78ac17 100644 --- a/contracts/token/ERC1155/ERC1155.sol +++ b/contracts/token/ERC1155/ERC1155.sol @@ -31,6 +31,9 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { // Used as the URI for all token types by relying on ID substition, e.g. https://token-cdn-domain/{id}.json string private _uri; + // Mapping token ID to that token being registered as existing (1 for existing, 0 for not existing) + mapping (uint256 => uint256) private _tokenExists; + /* * bytes4(keccak256('balanceOf(address,uint256)')) == 0x00fdd58e * bytes4(keccak256('balanceOfBatch(address[],uint256[])')) == 0x4e1273f4 @@ -229,6 +232,32 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _uri = newuri; } + /** + * @dev Register an `id` so other contract functionality knows this token actually + * exists and this ID is valid. Minting will automatically call this. + * If `sendEvent` is true, emits an event to flag the existence, see the spec: + * "To broadcast the existence of a token ID with no initial balance, the contract + * SHOULD emit the TransferSingle event from 0x0 to 0x0, with the token creator as + * _operator, and a _value of 0." + * Minting will call this without sending an event as a similar event is sent for + * the minting itself already. + */ + function _registerToken(uint256 id, bool sendEvent) internal virtual { + if (_tokenExists[id] == 0) { + _tokenExists[id] = 1; + if (sendEvent) { + emit TransferSingle(msg.sender, address(0), address(0), id, 0); + } + } + } + + /** + * @dev Returns whether the token `id` exists. Use {_registerToken} to set this flag. + */ + function _exists(uint256 id) internal view returns (bool) { + return _tokenExists[id] != 0; + } + /** * @dev Creates `amount` tokens of token type `id`, and assigns them to `account`. * @@ -247,6 +276,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data); + if (!_exists(id)) { + _registerToken(id, false); + } + _balances[id][account] = _balances[id][account].add(amount); emit TransferSingle(operator, address(0), account, id, amount); @@ -271,6 +304,9 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); for (uint i = 0; i < ids.length; i++) { + if (!_exists(ids[i])) { + _registerToken(ids[i], false); + } _balances[ids[i]][to] = amounts[i].add(_balances[ids[i]][to]); }