diff --git a/EIPS/eip-1155.md b/EIPS/eip-1155.md index 6ceeeb4e8b122f..ca70cc431ea9d0 100644 --- a/EIPS/eip-1155.md +++ b/EIPS/eip-1155.md @@ -43,20 +43,20 @@ pragma solidity ^0.5.8; */ interface ERC1155 /* is ERC165 */ { /** - @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning. - Operator MUST be msg.sender. - When minting/creating tokens, the `_from` field MUST be set to `0x0` - When burning/destroying tokens, the `_to` field MUST be set to `0x0` + @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "TransferSingle and TransferBatch event rules" section of the standard). + `_operator` MUST be msg.sender. + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address) + When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address) The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. 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. */ event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value); /** - @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning. - Operator MUST be msg.sender. - When minting/creating tokens, the `_from` field MUST be set to `0x0` - When burning/destroying tokens, the `_to` field MUST be set to `0x0` + @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "TransferSingle and TransferBatch event rules" section of the standard). + `_operator` MUST be msg.sender. + When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address) + When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address) The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. To broadcast the existence of multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0. */ @@ -70,7 +70,7 @@ interface ERC1155 /* is ERC165 */ { /** @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. - The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata JSON Schema". + The URI MUST point a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". */ event URI(string _value, uint256 indexed _id); @@ -154,8 +154,7 @@ interface ERC1155TokenReceiver { @notice Handle the receipt of a single ERC1155 token type. @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated. This function MUST return whether it accepts or rejects the transfer via the prescribed keccak256 generated values. - Return of any other value than the prescribed keccak256 generated values WILL result in the transaction being reverted. - Note: The contract address is always the message sender. + Return of any other value than the prescribed keccak256 generated values MUST result in the transaction being reverted. @param _operator The address which initiated the transfer (i.e. msg.sender) @param _from The address which previously owned the token @param _id The id of the token being transferred @@ -169,8 +168,7 @@ interface ERC1155TokenReceiver { @notice Handle the receipt of multiple ERC1155 token types. @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated. This function MUST return whether it accepts or rejects the transfer via the prescribed keccak256 generated values. - Return of any other value than the prescribed keccak256 generated values WILL result in the transaction being reverted. - Note: The contract address is always the message sender. + Return of any other value than the prescribed keccak256 generated values MUST result in the transaction being reverted. @param _operator The address which initiated the batch transfer (i.e. msg.sender) @param _from The address which previously owned the token @param _ids An array containing ids of each token being transferred (order and length must match _values array) @@ -188,75 +186,98 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op #### Scenarios -**_Scenario:_** The recipient is not a contract. -* onERC1155Received and onERC1155BatchReceived MUST NOT be called on an EOA account. +**_Scenario#1 :_** The recipient is not a contract. +* onERC1155Received and onERC1155BatchReceived MUST NOT be called on an EOA (Externally Owned Account). -**_Scenario:_** The transaction is not a mint/transfer of a token. +**_Scenario#2 :_** The transaction is not a mint/transfer of a token. * onERC1155Received and onERC1155BatchReceived MUST NOT be called outside of a mint or transfer process. -**_Scenario:_** The receiver does not implement the necessary ERC1155TokenReceiver interface function(s). +**_Scenario#3 :_** The receiver does not implement the necessary ERC1155TokenReceiver interface function(s). * The transfer MUST be reverted with the one caveat below. - If the tokens being sent are part of a hybrid implementation of another standard, that particular standard's rules on sending to a contract MAY now be followed instead. See "Compatibility with other standards" section. -**_Scenario:_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but returns an unknown value. +**_Scenario#4 :_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but returns an unknown value. * The transfer MUST be reverted. -**_Scenario:_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but throws an error. +**_Scenario#5 :_** The receiver implements the necessary ERC1155TokenReceiver interface function(s) but throws an error. * The transfer MUST be reverted. -**_Scenario:_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of one and only one balance change in the transaction (eg. safeTransferFrom called). -* All the balances in the transaction MUST have been updated to match the senders intent before any hook is called on a recipient. -* The appropriate choice of either onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. +**_Scenario#6 :_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of one and only one balance change (eg. safeTransferFrom called). +* All the balances in the transfer MUST have been updated to match the senders intent before any hook is called on a recipient. +* One of onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. * The onERC1155Received hook SHOULD be called on the recipient contract and its rules followed. - - If this hook is called it MUST NOT be called again on the recipient in this transaction. - - See "onERC1155Received common rules" for further rules that MUST be followed. -* The onERC1155BatchReceived hook MAY be called on the recipient contract and its rules followed - - See "onERC1155BatchReceived common rules" for further rules that MUST be followed. - -**_Scenario:_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of more than one balance change in the transaction (eg. safeBatchTransferFrom called). -* All the balances in the transaction MUST have been updated to match the senders intent before any hook is called on a recipient. -* The appropriate choice of either onERC1155Received or onERC1155BatchReceived MUST be called on the recipient. -* The onERC1155BatchReceived hook SHOULD be called on the recipient contract and its rules followed. - - If called the arguments MUST contain/list information on every balance change for the recipient (and only the recipient) in this transaction. - - See "onERC1155BatchReceived common rules" for further rules that MUST be followed. -* The onERC1155Received hook MAY be called on the recipient contract and its rules followed. - - If called it MUST be repeatedly called until information has been passed and return value checked for every balance change for the recipient (and only the recipient) in this transaction. - - See "onERC1155Received common rules" for further rules that MUST be followed. + - See "onERC1155Received rules" for further rules that MUST be followed. +* The onERC1155BatchReceived hook MAY be called on the recipient contract and its rules followed. + - See "onERC1155BatchReceived rules" for further rules that MUST be followed. + +**_Scenario#7 :_** The receiver implements the ERC1155TokenReceiver interface and is the recipient of more than one balance change (eg. safeBatchTransferFrom called). +* All the balances in the transfer MUST have been updated to match the senders intent before any hook is called on a recipient. +* onERC1155Received or onERC1155BatchReceived MUST be called on the recipient as many times as necessary such that every balance change for the recipient in the scenario is accounted for. + - The return magic value for every hook call MUST be checked and acted upon as per "onERC1155Received rules" and "onERC1155BatchReceived rules". +* The onERC1155BatchReceived hook SHOULD be called on the recipient contract and its rules followed. + - See "onERC1155BatchReceived rules" for further rules that MUST be followed. +* The onERC1155Received hook MAY be called on the recipient contract and its rules followed. + - See "onERC1155Received rules" for further rules that MUST be followed. #### Rules -**_onERC1155Received common rules:_** -* If this hook is called onERC1155BatchReceived MUST NOT also be called on the recipient in this transaction. -* The _operator argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). -* The _from argument MUST be the address of the holder whose balance is decreased. - - _from MUST be 0x0 for a mint. -* The _id argument MUST be the token type being transferred. -* The _value MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. -* The _data argument MUST contain the extra information provided by the sender (if any) for a transfer. -* The destination/to contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` +**_TransferSingle and TransferBatch event rules:_** +* TransferSingle SHOULD be used to indicate a single balance transfer has occurred between a `_from` and `_to` pair. + - It MAY be emitted multiple times to indicate multiple balance changes in the transaction, but note that TransferBatch is designed for this to reduce gas consumption. + - The `_operator` argument MUST be msg.sender. + - The `_from` argument MUST be the address of the holder whose balance is decreased. + - The `_to` argument MUST be the address of the recipient whose balance is increased. + - The `_id` argument MUST be the token type being transferred. + - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). +* TransferBatch SHOULD be used to indicate multiple balance transfers have occurred between a `_from` and `_to` pair. + - It MAY be emitted with a single element in the list to indicate a singular balance change in the transaction, but note that TransferSingle is designed for this to reduce gas consumption. + - The `_operator` argument MUST be msg.sender. + - The `_from` argument MUST be the address of the holder whose balance is decreased. + - The `_to` argument MUST be the address of the recipient whose balance is increased. + - The `_ids` argument MUST be the list of tokens being transferred. + - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). +* The total value transferred from address 0x0 minus the total value transferred to 0x0 MAY be used by clients and exchanges to be added to the "circulating supply" for a given token ID. +* 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. + +**_onERC1155Received rules:_** +* The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). +* The `_from` argument MUST be the address of the holder whose balance is decreased. + - `_from` MUST be 0x0 for a mint. +* The `_id` argument MUST be the token type being transferred. +* The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. +* The `_data` argument MUST contain the extra information provided by the sender (if any) for a transfer. +* The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_erc1155_tokens()"))` - If the return value is `bytes4(keccak256("accept_erc1155_tokens()"))` the transfer MUST be completed, unless other conditions necessitate a revert. -* The destination/to contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. +* The recipient contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. * If the return value is anything other than `bytes4(keccak256("accept_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. - -**_onERC1155BatchReceived common rules:_** -* If this hook is called onERC1155Received MUST NOT also be called on the recipient in this transaction. -* If this hook is called it MUST NOT be called again on the recipient in this transaction. -* The _operator argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). -* The _from argument MUST be the address of the holder whose balance is decreased. - - _from MUST be 0x0 for a mint. -* The _ids argument MUST be the list of tokens being transferred. -* The _values argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. -* The _data argument MUST contain the extra information provided by the sender (if any) for a transfer. -* The destination/to contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_batch_erc1155_tokens()"))` +* onERC1155Received MAY be called multiple times in a single transaction and the following requirements must be met: + - All callbacks represent mutually exclusive balance changes. + - The set of all callbacks describes all balance changes that occurred during the transaction. + +**_onERC1155BatchReceived rules:_** +* The `_operator` argument MUST be the address of the account/contract that initiated the transfer (i.e. msg.sender). +* The `_from` argument MUST be the address of the holder whose balance is decreased. + - `_from` MUST be 0x0 for a mint. +* The `_ids` argument MUST be the list of tokens being transferred. +* The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. +* The `_data` argument MUST contain the extra information provided by the sender (if any) for a transfer. +* The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("accept_batch_erc1155_tokens()"))` - If the return value is `bytes4(keccak256("accept_batch_erc1155_tokens()"))` the transfer MUST be completed, unless other conditions necessitate a revert. -* The destination/to contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. +* The recipient contract MAY reject an increase of its balance by returning the rejection magic value `bytes4(keccack256("reject_erc1155_tokens()"))`. - If the return value is `bytes4(keccak256("reject_erc1155_tokens()"))` the transaction MUST be reverted. * If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` or `bytes4(keccack256("reject_erc1155_tokens()"))` the transaction MUST be reverted. +* onERC1155BatchReceived MAY be called multiple times in a single transaction and the following requirements must be met: + - All callbacks represent mutually exclusive balance changes. + - The set of all callbacks describes all balance changes that occurred during the transaction. **_Implementation specific transfer api rules:_** * If implementation specific api functions are used to transfer 1155 tokens to a contract the appropriate hook(s) MUST still be called with the same rules as if safeTransferFrom/safeBatchTransferFrom was used. -* The appropriate events MUST be correctly emitted as if safeTransferFrom/safeBatchTransferFrom was used. +* The appropriate event(s) MUST be correctly emitted as if safeTransferFrom/safeBatchTransferFrom was used. ###### A solidity example of the keccak256 generated constants for the return magic is: - bytes4 constant public ERC1155_REJECTED = 0xafed434d; // keccak256("reject_erc1155_tokens()") @@ -265,8 +286,8 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op #### Compatibility with other standards -There have been requirements during the design discussions to have this standard be compatible with older standards when sending to contract addresses, specifically ERC721 at time of writing. -To cater for this there is some leeway with the rejection logic should a contract not implement the ERC1155TokenReceiver as per "Safe Transfer Rules" section above, specifically the scenario "The receiver does not implement the necessary ERC1155TokenReceiver interface function(s)". +There have been requirements during the design discussions to have this standard be compatible with older standards when sending to contract addresses, specifically ERC-721 at time of writing. +To cater for this there is some leeway with the rejection logic should a contract not implement the ERC1155TokenReceiver as per "Safe Transfer Rules" section above, specifically "Scenario#3 : The receiver does not implement the necessary ERC1155TokenReceiver interface function(s)". In that particular scenario if the 1155 implementation is also a hybrid implementation of another token standard, it MAY now follow the secondary standard's rules when transferring token(s) to a contract address. *__Note that a pure implementation of a single standard is recommended__* rather than a hybrid solution, but an example of a hybrid 1155+721 contract is linked in the references section under implementations. @@ -297,7 +318,7 @@ interface ERC1155Metadata_URI { /** @notice A distinct Uniform Resource Identifier (URI) for a given token. @dev URIs are defined in RFC 3986. - The URI may point to a JSON file that conforms to the "ERC-1155 Metadata JSON Schema". + The URI may point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". @return URI string */ function uri(uint256 _id) external view returns (string memory);