mirror of https://github.com/status-im/EIPs.git
Automatically merged updates to draft EIP(s) 1155 (#2083)
Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing
This commit is contained in:
parent
9af2a9b1ef
commit
4b676ff535
|
@ -160,7 +160,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 `bytes4(keccak256("accept_erc1155_tokens()"))` (i.e. 0x4dc21a2f) if it accepts the transfer.
|
||||
This function MUST return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (i.e. 0xf23a6e61) if it accepts the transfer.
|
||||
This function MUST revert if it rejects the transfer.
|
||||
Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.
|
||||
@param _operator The address which initiated the transfer (i.e. msg.sender)
|
||||
|
@ -168,14 +168,14 @@ interface ERC1155TokenReceiver {
|
|||
@param _id The ID of the token being transferred
|
||||
@param _value The amount of tokens being transferred
|
||||
@param _data Additional data with no specified format
|
||||
@return `bytes4(keccak256("accept_erc1155_tokens()"))`
|
||||
@return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
|
||||
*/
|
||||
function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4);
|
||||
|
||||
/**
|
||||
@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 `bytes4(keccak256("accept_batch_erc1155_tokens()"))` (i.e. 0xac007889) if it accepts the transfer(s).
|
||||
This function MUST return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (i.e. 0xbc197c81) if it accepts the transfer(s).
|
||||
This function MUST revert if it rejects the transfer(s).
|
||||
Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.
|
||||
@param _operator The address which initiated the batch transfer (i.e. msg.sender)
|
||||
|
@ -183,7 +183,7 @@ interface ERC1155TokenReceiver {
|
|||
@param _ids An array containing ids of each token being transferred (order and length must match _values array)
|
||||
@param _values An array containing amounts of each token being transferred (order and length must match _ids array)
|
||||
@param _data Additional data with no specified format
|
||||
@return `bytes4(keccak256("accept_batch_erc1155_tokens()"))`
|
||||
@return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
|
||||
*/
|
||||
function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4);
|
||||
|
||||
|
@ -199,7 +199,7 @@ interface ERC1155TokenReceiver {
|
|||
|
||||
### Safe Transfer Rules
|
||||
|
||||
To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST operate with respect to the `ERC1155TokenReceiver` hook functions, a list of scenarios and rules follows.
|
||||
To be more explicit about how the standard `safeTransferFrom` and `safeBatchTransferFrom` functions MUST operate with respect to the `ERC1155TokenReceiver` hook functions, a list of scenarios and rules follows.
|
||||
|
||||
#### Scenarios
|
||||
|
||||
|
@ -219,18 +219,18 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op
|
|||
**_Scenario#5 :_** The receiver implements the necessary `ERC1155TokenReceiver` interface function(s) but throws an error.
|
||||
* The transfer MUST be reverted.
|
||||
|
||||
**_Scenario#6 :_** The receiver implements the `ERC1155TokenReceiver` interface and is the recipient of one and only one balance change (e.g. 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.
|
||||
* All the transfer events for the transfer MUST have been emitted to reflect the balance changes before any hook is called on a recipient.
|
||||
* One of `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 (e.g. `safeTransferFrom` called).
|
||||
* The balances for the transfer MUST have been updated before the `ERC1155TokenReceiver` hook is called on a recipient contract.
|
||||
* The transfer event MUST have been emitted to reflect the balance changes before the `ERC1155TokenReceiver` hook is called on the recipient contract.
|
||||
* One of `onERC1155Received` or `onERC1155BatchReceived` MUST be called on the recipient contract.
|
||||
* The `onERC1155Received` hook SHOULD be called on the recipient contract and its rules 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 (e.g. 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.
|
||||
* All the transfer events for the transfer MUST have been emitted to reflect the balance changes before any hook is called on a recipient.
|
||||
**_Scenario#7 :_** The receiver implements the `ERC1155TokenReceiver` interface and is the recipient of more than one balance change (e.g. `safeBatchTransferFrom` called).
|
||||
* All the balances in the transfer related to the next hook call MUST have been updated before that `ERC1155TokenReceiver` hook is called on a recipient contract.
|
||||
* All transfer events MUST have been emitted to reflect current balance changes before an `ERC1155TokenReceiver` hook is called on the recipient contract.
|
||||
* `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.
|
||||
|
@ -244,6 +244,14 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op
|
|||
* The `_data` argument MAY be re-purposed for the new context.
|
||||
* If forwarding fails the transaction MAY be reverted.
|
||||
- If the contract logic wishes to keep the ownership of the token(s) itself in this case it MAY do so.
|
||||
|
||||
**_Scenario#9 :_** You are transferring tokens via a non-standard api call i.e. an implementation specific api and NOT `safeTransferFrom` or `safeBatchTransferFrom`.
|
||||
* In this scenario all balance updates and events outputs rules are the same as if a standard function had been called.
|
||||
- i.e. an external viewer should still be able to query a balance via a function and it be identical to the balance as determined by `TransferSingle` and '`TransferBatch` events alone.
|
||||
* If the receiver is a contract the `ERC1155TokenReceiver` hooks still need to be called on it and the return values respected the same as if a standard function had been called.
|
||||
- However while the `safeTransferFrom` or `safeBatchTransferFrom` functions MUST revert if a receiving contract does not implement the `ERC1155TokenReceiver` interface, a non-standard function MAY proceed with the transfer.
|
||||
- See "Implementation specific transfer api rules".
|
||||
|
||||
|
||||
#### Rules
|
||||
|
||||
|
@ -300,11 +308,11 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op
|
|||
* 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 information provided by the sender for the transfer with its contents unaltered.
|
||||
- i.e. it MUST pass on the unaltered `_data` argument sent via the `safeTransferFrom` or `safeBatchTransferFrom` call for this 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 or MUST revert if any other conditions are not met for success.
|
||||
* The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
|
||||
- If the return value is `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` the transfer MUST be completed or MUST revert if any other conditions are not met for success.
|
||||
* The recipient contract MAY reject an increase of its balance by calling revert.
|
||||
- If recipient contract throws/reverts the transaction MUST be reverted.
|
||||
* If the return value is anything other than `bytes4(keccak256("accept_erc1155_tokens()"))` the transaction MUST be reverted.
|
||||
* If the return value is anything other than `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` the transaction MUST be reverted.
|
||||
* `onERC1155Received` (and/or `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 calls to `onERC1155Received` and `onERC1155BatchReceived` describes all balance changes that occurred during the transaction in the order submitted.
|
||||
|
@ -317,11 +325,11 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op
|
|||
* 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 information provided by the sender for the transfer with its contents unaltered.
|
||||
- i.e. it MUST pass on the unaltered `_data` argument sent via the `safeBatchTransferFrom` call for this 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 or MUST revert if any other conditions are not met for success.
|
||||
* The recipient contract MAY accept an increase of its balance by returning the acceptance magic value `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
|
||||
- If the return value is `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` the transfer MUST be completed or MUST revert if any other conditions are not met for success.
|
||||
* The recipient contract MAY reject an increase of its balance by calling revert.
|
||||
- If recipient contract throws/reverts the transaction MUST be reverted.
|
||||
* If the return value is anything other than `bytes4(keccak256("accept_batch_erc1155_tokens()"))` the transaction MUST be reverted.
|
||||
* If the return value is anything other than `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` the transaction MUST be reverted.
|
||||
* `onERC1155BatchReceived` (and/or `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 calls to `onERC1155Received` and `onERC1155BatchReceived` describes all balance changes that occurred during the transaction in the order submitted.
|
||||
|
@ -338,26 +346,42 @@ To be more explicit about how safeTransferFrom and safeBatchTransferFrom MUST op
|
|||
- It MUST NOT consume more than 5,000 gas.
|
||||
|
||||
**_Implementation specific transfer api rules:_**
|
||||
* If implementation specific api functions are used to transfer 1155 tokens to a contract, the safeTransferFrom, or safeBatchTransferFrom (as appropriate) rules MUST be followed.
|
||||
* If implementation specific api functions are used to transfer ERC-1155 tokens to a contract, the `safeTransferFrom`, or `safeBatchTransferFrom` (as appropriate) rules MUST still be followed if the receiver implements the `ERC1155TokenReceiver` interface. If not it is up to the implementation to revert or proceed.
|
||||
* An example:
|
||||
1. A approved user calls a function such as `function myTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values);`.
|
||||
2. `myTransferFrom` updates the balances for `_from` and `_to` addresses for all `_ids` and `_values`.
|
||||
3. `myTransferFrom` emits `TransferBatch` with the details of what was transferred from address `_from` to address `_to`.
|
||||
4. `myTransferFrom` checks if `_to` is a contract address and determines that it is (if not, then the transfer can be considered successful).
|
||||
5. `myTransferFrom` calls `onERC1155BatchReceived` on `_to` and it reverts or returns an unknown value (if it had returned `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` the transfer can be considered successful).
|
||||
6. At this point `myTransferFrom` MAY decide to revert the transaction immediately as receipt of the tokens was not explicitly accepted by the `onERC1155BatchReceived` function.
|
||||
7. If `myTransferFrom` wishes to continue it MUST call `isERC1155TokenReceiver()` on `_to` and if it returns `bytes4(keccak256("isERC1155TokenReceiver()"))` the transaction MUST be reverted, as it is a valid receiver and the previous step failed.
|
||||
8. If the above call to `isERC1155TokenReceiver()` on `_to` reverts or returns an unknown value the `myTransferFrom` function MAY consider this transfer successful (__NOTE__: this MAY result in unrecoverable tokens if sent to an address that does not expect to receive ERC-1155 tokens).
|
||||
* The above example is not exhaustive but illustrates the major points (and shows that most are shared with `safeTransferFrom` and `safeBatchTransferFrom`):
|
||||
- Balances that are updated MUST have equivalent transfer events emitted.
|
||||
- A receiver address has to be checked if it is a contract and if so relevant `ERC1155TokenReceiver` hook function(s) have to be called on it.
|
||||
- Balances (and events associated) that are referenced in a call to a receiver hook MUST be updated (and emitted) before the `ERC1155TokenReceiver` hook is called.
|
||||
- The return values of the `ERC1155TokenReceiver` hook functions that are called MUST be respected if they are implemented.
|
||||
- Only in the case that a recipient contract does NOT implement the necessary `ERC1155TokenReceiver` hook functions can a non-standard implementation allow tokens to be sent to it. A standard function MUST always revert regardless (unless it is a hybrid implementation see "Compatibility with other standards").
|
||||
|
||||
|
||||
###### A solidity example of the keccak256 generated constants for the return magic is:
|
||||
- bytes4 constant public ERC1155_ACCEPTED = 0x4dc21a2f; // bytes4(keccak256("accept_erc1155_tokens()"))
|
||||
- bytes4 constant public ERC1155_BATCH_ACCEPTED = 0xac007889; // bytes4(keccak256("accept_batch_erc1155_tokens()"))
|
||||
- bytes4 constant public ERC1155_ACCEPTED = 0xf23a6e61; // bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))
|
||||
- bytes4 constant public ERC1155_BATCH_ACCEPTED = 0xbc197c81; // bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))
|
||||
|
||||
#### Compatibility with other standards
|
||||
|
||||
There have been requirements during the design discussions to have this standard be compatible with existing standards when sending to contract addresses, specifically ERC-721 at time of writing.
|
||||
To cater for this scenario, 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)".
|
||||
|
||||
Hence in a hybrid 1155 contract implementation an extra call MUST be made on the recipient contract and checked before any hook calls to `onERC1155Received` or `onERC1155BatchReceived` are made.
|
||||
Hence in a hybrid ERC-1155 contract implementation an extra call MUST be made on the recipient contract and checked before any hook calls to `onERC1155Received` or `onERC1155BatchReceived` are made.
|
||||
Order of operation MUST therefore be:
|
||||
1. The implementation MUST call the function `isERC1155TokenReceiver` on the recipient, providing at least 5,000 gas.
|
||||
2. If the function call succeeds and the return value is `bytes4(keccak256("isERC1155TokenReceiver()"))` the implementation proceeds as a regular 1155 implementation, with the call(s) to the `onERC1155Received` or `onERC1155BatchReceived` hooks and rules associated.
|
||||
3. If the function call fails or the return value is NOT `bytes4(keccak256("isERC1155TokenReceiver()"))` the implementation can assume the contract recipient is not an `ERC1155TokenReceiver` and follow its other standard's rules for transfers.
|
||||
1. The implementation MUST call the function `isERC1155TokenReceiver` on the recipient contract, providing at least 5,000 gas.
|
||||
2. If the function call succeeds and the return value is `bytes4(keccak256("isERC1155TokenReceiver()"))` the implementation proceeds as a regular ERC-1155 implementation, with the call(s) to the `onERC1155Received` or `onERC1155BatchReceived` hooks and rules associated.
|
||||
3. If the function call fails or the return value is NOT `bytes4(keccak256("isERC1155TokenReceiver()"))` the implementation can assume the recipient contract is not an `ERC1155TokenReceiver` and follow its other standard's rules for transfers.
|
||||
|
||||
*__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.
|
||||
*__Note that a pure implementation of a single standard is recommended__* rather than a hybrid solution, but an example of a hybrid ERC-1155/ERC-721 contract is linked in the references section under implementations.
|
||||
|
||||
An important consideration is that even if the tokens are sent with another standard's rules the *__1155 transfer events MUST still be emitted.__* This is so the balances can still be determined via events alone as per 1155 standard rules.
|
||||
An important consideration is that even if the tokens are sent with another standard's rules the *__1155 transfer events MUST still be emitted.__* This is so the balances can still be determined via events alone as per ERC-1155 standard rules.
|
||||
|
||||
|
||||
### Metadata
|
||||
|
|
Loading…
Reference in New Issue