Automatically merged updates to draft EIP(s) 998

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:
Nick Mudge 2018-08-01 01:49:57 -07:00 committed by EIP Automerge Bot
parent 7bccb190f5
commit 2cf76d1436
1 changed files with 144 additions and 87 deletions

View File

@ -11,35 +11,43 @@ requires: 721, 165
---
## Simple Summary
An extension of the [ERC721 standard](https://eips.ethereum.org/EIPS/eip-721) to enable ERC721 tokens to own other ERC721 tokens and ERC20 tokens.
An extension of the [ERC20](https://eips.ethereum.org/EIPS/eip-20) and [ERC223](https://github.com/ethereum/EIPs/issues/223) standards to enable ERC20 and ERC223 tokens to be owned by ERC721 tokens.
This specification covers four different kinds of composable tokens:
1. [ERC998ERC721 top-down composable tokens that receive, hold and transfer ERC721 tokens](#erc721-top-down-composable)
2. [ERC998ERC20 top-down composable tokens that receive, hold and transfer ERC20 tokens](#erc20-top-down-composable)
3. [ERC998ERC721 bottom-up composable tokens that attach themselves to other ERC721 tokens.](#erc721-bottom-up-composable)
4. [ERC998ERC20 bottom-up composable tokens that attach themselves to ERC721 tokens.](#erc20-bottom-up-composable)
An extension of the [ERC721 standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md) to enable ERC721 tokens to own other ERC721 tokens and ERC20 tokens.
## Abstract
An ERC988 composable is an ERC721 token with additional functionality for owning or being owned by other ERC721 tokens. An ERC998 composable can also own ERC20 tokens.
An ERC721 token owns another token if the the ownership of the token has been transferred to it.
1. An ERC988ERC721 top-down composable is an ERC721 token with additional functionality for owning other ERC721 tokens.
2. An ERC998ERC20 top-down composable is an ERC721 token with additional functionality for owning ERC20 tokens.
3. An ERC998ERC721 bottom-up composable is an ERC721 token with additional functionality for being owned by an ERC721 token.
4. An ERC998ERC20 bottom-up composable is an ERC20 token with additional functionality for being owned by an ERC721 token.
A top-down composable contract stores and keeps track of child tokens for each of its tokens.
A bottom-up composable contract stores and keeps track of a parent token for each its tokens.
With either kind of composable it is possible to compose lists or trees of ERC721 tokens connected by ownership. Any such structure will have a single owner address at the root of the structure that is the owner of the entire composition. The entire composition can be transferred with one transaction by changing the root owner.
With composable tokens it is possible to compose lists or trees of ERC721 and ERC20 tokens connected by ownership. Any such structure will have a single owner address at the root of the structure that is the owner of the entire composition. The entire composition can be transferred with one transaction by changing the root owner.
Both kinds of composable, top-down and bottom-up, have their advantages and disadvantages which are explained in the Rational section. It is possible for a composable token to be one or both kinds of composable.
Different composables, top-down and bottom-up, have their advantages and disadvantages which are explained in the [Rational section](#rationale). It is possible for a token to be one or more kinds of composable token.
## Specification
This specification specifies:
1. [ERC721 top-down composable tokens that receive, hold and transfer ERC721 tokens](#erc721-top-down-composable)
2. [ERC20 top-down composable tokens that receive, hold and transfer ERC20 tokens](#erc20-top-down-composable)
3. [ERC721 bottom-up composable tokens that attach themselves to other ERC721 tokens.](#erc721-bottom-up-composable)
4. [ERC20 bottom-up composable tokens that attach themselves to other ERC20 tokens.](#erc20-bottom-up-composable)
### ERC721
Both ERC721 top-down and ERC721 bottom-up composable contracts must implement the [ERC721 interface](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md).
ERC998ERC721 top-down, ERC998ERC20 top-down, and ERC998ERC721 bottom-up composable contracts must implement the [ERC721 interface](https://eips.ethereum.org/EIPS/eip-721).
### ERC20
ERC998ERC20 bottom-up composable contracts must implement the [ERC20 interface](https://eips.ethereum.org/EIPS/eip-20).
### ERC165
@ -47,7 +55,7 @@ The [ERC165 standard](https://eips.ethereum.org/EIPS/eip-165) must be applied to
### Authentication
Authenticating whether a user or contract can execute some action works the same for both top-down and bottom-up composables.
Authenticating whether a user or contract can execute some action works the same for both ERC998ERC721 top-down and ERC998ERC721 bottom-up composables.
A `rootOwner` refers to the owner address at the top of a tree of composables and ERC721 tokens.
@ -82,7 +90,7 @@ function getApproved(uint256 _tokenId) public view returns (address) {
The rootOwner of a composable is gotten by calling `rootOwnerOf(uint256 _tokenId)` or `rootOwnerOfChild(address _childContract, uint256 _childTokenId)`. These functions are used by top-down and bottom-up composables to traverse up the tree of composables and ERC721 tokens to find the rootOwner.
Top-down and bottom-up composables are interoperable with each other. It is possible for a top-down composable to own a bottom-up composable or for a top-down composable to own an ERC721 token that owns a bottom-up token. In any configuration calling `rootOwnerOf(uint256 _tokenID)` on the bottom composable will return the owner address at the top of the ownership tree.
ERC998ERC721 top-down and bottom-up composables are interoperable with each other. It is possible for a top-down composable to own a bottom-up composable or for a top-down composable to own an ERC721 token that owns a bottom-up token. In any configuration calling `rootOwnerOf(uint256 _tokenID)` on a composable will return the root owner address at the top of the ownership tree.
Tokens/contracts that implement the above authentication and traversal functionality are "composable aware".
@ -1053,68 +1061,93 @@ The complete interface is below.
/// Note: The ERC-165 identifier for this interface is 0xffafa991
interface ERC998ERC20BottomUp {
/// @dev This emits when a token is transferred to an ERC721 token
/// @param _toContract The contract the token is transferred to
/// @param _toTokenId The token the token is transferred to
/// @param _amount The amount of tokens transferred
event TransferToParent(
address indexed _toContract,
uint256 indexed _toTokenId,
uint256 _amount
);
/// @dev This emits when a token is transferred to an ERC721 token
/// @param _toContract The contract the token is transferred to
/// @param _toTokenId The token the token is transferred to
/// @param _amount The amount of tokens transferred
event TransferToParent(
address indexed _toContract,
uint256 indexed _toTokenId,
uint256 _amount
);
/// @dev This emits when a token is transferred from an ERC721 token
/// @param _fromContract The contract the token is transferred from
/// @param _fromTokenId The token the token is transferred from
/// @param _amount The amount of tokens transferred
event TransferFromParent(
address indexed _fromContract,
uint256 indexed _fromTokenId,
uint256 _amount
);
/// @dev This emits when a token is transferred from an ERC721 token
/// @param _fromContract The contract the token is transferred from
/// @param _fromTokenId The token the token is transferred from
/// @param _amount The amount of tokens transferred
event TransferFromParent(
address indexed _fromContract,
uint256 indexed _fromTokenId,
uint256 _amount
);
/// @notice Get the balance of a non-fungible parent token
/// @param _tokenContract The contract tracking the parent token
/// @param _tokenId The ID of the parent token
/// @return amount The balance of the token
function balanceOfToken(address _tokenContract, uint256 _tokenId)
external
view
returns (uint256 amount);
/// @notice Get the balance of a non-fungible parent token
/// @param _tokenContract The contract tracking the parent token
/// @param _tokenId The ID of the parent token
/// @return amount The balance of the token
function balanceOfToken(
address _tokenContract,
uint256 _tokenId
)
external
view
returns (uint256 amount);
/// @notice Transfer tokens from owner address to a token
/// @param _from The owner address
/// @param _toContract The ERC721 contract of the receiving token
/// @param _toToken The receiving token
/// @param _amount The amount of tokens to transfer
function transferToParent(address _from, address _toContract, uint256 _toTokenId, uint256 _amount)
external;
/// @notice Transfer tokens from owner address to a token
/// @param _from The owner address
/// @param _toContract The ERC721 contract of the receiving token
/// @param _toToken The receiving token
/// @param _amount The amount of tokens to transfer
function transferToParent(
address _from,
address _toContract,
uint256 _toTokenId,
uint256 _amount
)
external;
/// @notice Transfer token from a token to an address
/// @param _fromContract The address of the owning contract
/// @param _fromTokenId The owning token
/// @param _to The address the token is transferred to
/// @param _amount The amount of tokens to transfer
function transferFromParent(address _fromContract, uint256 _fromTokenId, address _to, uint256 _amount)
external;
/// @notice Transfer token from a token to an address
/// @param _fromContract The address of the owning contract
/// @param _fromTokenId The owning token
/// @param _to The address the token is transferred to
/// @param _amount The amount of tokens to transfer
function transferFromParent(
address _fromContract,
uint256 _fromTokenId,
address _to,
uint256 _amount
)
external;
/// @notice Transfer token from a token to an address, using ERC223 semantics
/// @param _fromContract The address of the owning contract
/// @param _fromTokenId The owning token
/// @param _to The address the token is transferred to
/// @param _amount The amount of tokens to transfer
/// @param _data Additional data with no specified format, can be used to specify the sender tokenId
function transferFromParentERC223(address _fromContract, uint256 _fromTokenId, address _to, uint256 _amount, bytes _data)
external;
/// @notice Transfer token from a token to an address, using ERC223 semantics
/// @param _fromContract The address of the owning contract
/// @param _fromTokenId The owning token
/// @param _to The address the token is transferred to
/// @param _amount The amount of tokens to transfer
/// @param _data Additional data with no specified format, can be used to specify the sender tokenId
function transferFromParentERC223(
address _fromContract,
uint256 _fromTokenId,
address _to,
uint256 _amount,
bytes _data
)
external;
/// @notice Transfer a token from a token to another token
/// @param _fromContract The address of the owning contract
/// @param _fromTokenId The owning token
/// @param _toContract The ERC721 contract of the receiving token
/// @param _toToken The receiving token
/// @param _amount The amount tokens to transfer
function transferAsChild(address _fromContract, uint256 _fromTokenId, address _toContract, uint256 _toTokenId, uint256 _amount)
external;
/// @notice Transfer a token from a token to another token
/// @param _fromContract The address of the owning contract
/// @param _fromTokenId The owning token
/// @param _toContract The ERC721 contract of the receiving token
/// @param _toToken The receiving token
/// @param _amount The amount tokens to transfer
function transferAsChild(
address _fromContract,
uint256 _fromTokenId,
address _toContract,
uint256 _toTokenId,
uint256 _amount
)
external;
}
```
@ -1124,10 +1157,13 @@ interface ERC998ERC20BottomUp {
/// @param _tokenContract The contract tracking the parent token
/// @param _tokenId The ID of the parent token
/// @return amount The balance of the token
function balanceOfToken(address _tokenContract, uint256 _tokenId)
external
view
returns (uint256 amount);
function balanceOfToken(
address _tokenContract,
uint256 _tokenId
)
external
view
returns (uint256 amount);
```
This function returns the balance of a non-fungible token. It mirrors the standard ERC20 method `balanceOf`, but accepts the address of the parent token's contract, and the parent token's ID. This method behaves identically to `balanceOf`, but checks for ownership by ERC721 tokens rather than user addresses.
@ -1139,22 +1175,31 @@ This function returns the balance of a non-fungible token. It mirrors the standa
/// @param _toContract The ERC721 contract of the receiving token
/// @param _toToken The receiving token
/// @param _amount The amount of tokens to transfer
function transferToParent(address _from, address _toContract, uint256 _toTokenId, uint256 _amount)
external;
function transferToParent(
address _from,
address _toContract,
uint256 _toTokenId,
uint256 _amount
)
external;
```
This function transfers an amount of tokens from a user address to an ERC721 token. This function MUST ensure that the recipient contract implements ERC721 using the ERC165 `supportsInterface` function. This function SHOULD ensure that the recipient token actually exists, by calling `ownerOf` on the recipient token's contract, and ensuring it neither throws nor returns the zero address. This function MUST emit the `TransferToParent` event upon a successful transfer (in addition to the standard ERC20 `Transfer` event!). This function MUST throw if the `_from` account balance does not have enough tokens to spend.
#### transferFromParent
```
solidity
```solidity
/// @notice Transfer token from a token to an address
/// @param _fromContract The address of the owning contract
/// @param _fromTokenId The owning token
/// @param _to The address the token is transferred to
/// @param _amount The amount of tokens to transfer
function transferFromParent(address _fromContract, uint256 _fromTokenId, address _to, uint256 _amount)
external;
function transferFromParent(
address _fromContract,
uint256 _fromTokenId,
address _to,
uint256 _amount
)
external;
```
This function transfers an amount of tokens from an ERC721 token to an address. This function MUST emit the `TransferFromParent` event upon a successful transfer (in addition to the standard ERC20 `Transfer` event!). This function MUST throw if the balance of the sender ERC721 token is less than the `_amount` specified. This function MUST verify that the `msg.sender` owns the sender ERC721 token, and MUST throw otherwise.
@ -1167,13 +1212,19 @@ This function transfers an amount of tokens from an ERC721 token to an address.
/// @param _to The address the token is transferred to
/// @param _amount The amount of tokens to transfer
/// @param _data Additional data with no specified format, can be used to specify the sender tokenId
function transferFromParentERC223(address _fromContract, uint256 _fromTokenId, address _to, uint256 _amount, bytes _data)
external;
function transferFromParentERC223(
address _fromContract,
uint256 _fromTokenId,
address _to,
uint256 _amount,
bytes _data
)
external;
```
This function transfers an amount of tokens from an ERC721 token to an address. This function has identical requirements to `transferFromParent`, except that it additionally MUST invoke `tokenFallback` on the recipient address, if the address is a contract, as specified by ERC223.
### transferAsChild
#### transferAsChild
```solidity
/// @notice Transfer a token from a token to another token
/// @param _fromContract The address of the owning contract
@ -1181,8 +1232,14 @@ This function transfers an amount of tokens from an ERC721 token to an address.
/// @param _toContract The ERC721 contract of the receiving token
/// @param _toToken The receiving token
/// @param _amount The amount tokens to transfer
function transferAsChild(address _fromContract, uint256 _fromTokenId, address _toContract, uint256 _toTokenId, uint256 _amount)
external;
function transferAsChild(
address _fromContract,
uint256 _fromTokenId,
address _toContract,
uint256 _toTokenId,
uint256 _amount
)
external;
```
This function transfers an amount of tokens from an ERC721 token to another ERC721 token. This function MUST emit BOTH the `TransferFromParent` and `TransferToParent` events (in addition to the standard ERC20 `Transfer` event!). This function MUST throw if the balance of the sender ERC721 token is less than the `_amount` specified. This function MUST verify that the `msg.sender` owns the sender ERC721 token, and MUST throw otherwise. This function MUST ensure that the recipient contract implements ERC721 using the ERC165 `supportsInterface` function. This function SHOULD ensure that the recipient token actually exists, by calling `ownerOf` on the recipient token's contract, and ensuring it neither throws nor returns the zero address.