From 70204b7a1ecdcaf1427a8dac45c828d3df650344 Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Mon, 30 May 2022 00:26:08 -0700 Subject: [PATCH 01/12] Creates EIP-XXXX: Soulbound Token --- EIPS/eip-xxx.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 EIPS/eip-xxx.md diff --git a/EIPS/eip-xxx.md b/EIPS/eip-xxx.md new file mode 100644 index 0000000000000..a37d1abe46bec --- /dev/null +++ b/EIPS/eip-xxx.md @@ -0,0 +1,62 @@ +--- +eip: +title: Soulbound Token +description: A token that is attached to a "soul" at mint time and cannot be transferred after that. +author: Micah Zoltu (@MicahZoltu) +discussions-to: https://ethereum-magicians.org/t/eip-xxxx-soulbound-token/9417 +status: Draft +type: Standards Track +category: ERC +created: 2022-05-30 +requires: 721 +--- + +## Abstract +A soulbound token is a token that is bound to another ERC-721 token when it is minted, and cannot be transferred/moved after that. + +## Specification +```solidity +interface IERCXXXX { + // fired anytime a new instance of this token is minted + // this event **MUST NOT** be fired twice for the same `tokenId` + event Mint(uint256 indexed tokenId, address indexed erc721Token, uint256 indexed erc721TokenId); + + // returns the ERC-721 token that owns this token. + // this function **MUST** throw if the token hasn't been minted yet + // this function **MUST** always return the same result every time it is called after it has been minted + // this function **MUST** return the same value as found in the original `Mint` event for the token + function ownerOf(uint256 index) external view returns (address erc721Token, uint256 erc721TokenId); + + // returns a censorship resistant URI with details about this token collection + // the metadata returned by this is merged with the metata return by `tokenUri(uint256)` + // the tokenUri **MUST** be immutable and content addressable (e.g., ipfs://) + // the tokenUri **MUST NOT** point at mutable/censorable content (e.g., https://) + // data from `tokenUri` takes precedent over data returned by this method + // any external links referenced by the content at `tokenUri` also **MUST** follow all of the above rules + function collectionUri() external view returns (string tokenUri); + + // returns a censorship resistant URI with details about this token instance + // the tokenUri **MUST** be immutable and content addressable (e.g., ipfs://) + // the tokenUri **MUST NOT** point at mutable/censorable content (e.g., https://) + // data from this takes precedent over data returned by `collectionUri` + // any external links referenced by the content at `tokenUri` also **MUST** follow all of the above rules + function tokenUri(uint256 tokenId) external view returns (string tokenUri); +} +``` + +## Rationale +### Immutability +By requiring that tokens can never move, we both guarantee non-seperability and non-mergability among collections of soulbound tokens that are bound to a single NFT while simultaneously allowing users to aggressively cache results. +### Content Addressible URIs Required +Soulbound tokens are meant to be permanent badges/indicators attached to a persona. This means that not only can the user not transfer ownership, but the minter also cannot withdraw/transfer/change ownership as well. This includes mutating or removing any remote content as a means of censoring or manipulating specific users. + +## Backwards Compatibility +This is a new tokene type and is not meant to be backward compatible with any existing tokens other than using ERC-721 as souls. + +## Security Considerations +Users of tokens that claim to implement this EIP must be diligent in verifying they actually do. A token author can create a token that, upon initial probing of the API surface, may appear to follow the rulse when in reality it doesn't. For example, the contract could allow transfers via some mechanism and simply not utilize them initially. + +It should also be made clear that Soulbound tokens are not bound to a human, they are bound to a persona. A persona is any actor (which could be a group of humans) that collects multiple soulbound tokens over time to build up a collection of badges. This persona may transfer to another human, or to another group of humans, and anyone interacting with a persona should not assume that there is a single permanent immutable human behind that persona. + +## Copyright +Copyright and related rights waived via [CC0](../LICENSE.md). From e8d951f47e0ee26936baa734679dfe2d0170cd94 Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Mon, 30 May 2022 00:27:40 -0700 Subject: [PATCH 02/12] Updates EIP number --- EIPS/{eip-xxx.md => eip-5114.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename EIPS/{eip-xxx.md => eip-5114.md} (97%) diff --git a/EIPS/eip-xxx.md b/EIPS/eip-5114.md similarity index 97% rename from EIPS/eip-xxx.md rename to EIPS/eip-5114.md index a37d1abe46bec..85cfaf5dc7bf6 100644 --- a/EIPS/eip-xxx.md +++ b/EIPS/eip-5114.md @@ -1,9 +1,9 @@ --- -eip: +eip: 5114 title: Soulbound Token description: A token that is attached to a "soul" at mint time and cannot be transferred after that. author: Micah Zoltu (@MicahZoltu) -discussions-to: https://ethereum-magicians.org/t/eip-xxxx-soulbound-token/9417 +discussions-to: https://ethereum-magicians.org/t/eip-5114-soulbound-token/9417 status: Draft type: Standards Track category: ERC From a703f6d45d323be7a2450ae8ca81628921b54a96 Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Mon, 30 May 2022 00:29:55 -0700 Subject: [PATCH 03/12] Update eip-5114.md --- EIPS/eip-5114.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index 85cfaf5dc7bf6..fee962d9eb1e3 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -49,6 +49,8 @@ interface IERCXXXX { By requiring that tokens can never move, we both guarantee non-seperability and non-mergability among collections of soulbound tokens that are bound to a single NFT while simultaneously allowing users to aggressively cache results. ### Content Addressible URIs Required Soulbound tokens are meant to be permanent badges/indicators attached to a persona. This means that not only can the user not transfer ownership, but the minter also cannot withdraw/transfer/change ownership as well. This includes mutating or removing any remote content as a means of censoring or manipulating specific users. +### No Specification for tokenUri Data Format +The format of the data pointed to by `collectionUri()` and `tokenUri(uint256)` is intentionally left out of this standard in favor of separate standards that can be iterated on in the future. The immutability constraints are the only thing defined by this to ensure that the spirit of this token is maintained, regardless of the specifics of the data format. ## Backwards Compatibility This is a new tokene type and is not meant to be backward compatible with any existing tokens other than using ERC-721 as souls. From bc9e1d51b5bc11ca1bfee9bb449f36e79ed97254 Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Mon, 30 May 2022 05:18:21 -0700 Subject: [PATCH 04/12] Update EIPS/eip-5114.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tim Daubenschütz --- EIPS/eip-5114.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index fee962d9eb1e3..3914812e6d46c 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -28,7 +28,7 @@ interface IERCXXXX { function ownerOf(uint256 index) external view returns (address erc721Token, uint256 erc721TokenId); // returns a censorship resistant URI with details about this token collection - // the metadata returned by this is merged with the metata return by `tokenUri(uint256)` + // the metadata returned by this is merged with the metadata return by `tokenUri(uint256)` // the tokenUri **MUST** be immutable and content addressable (e.g., ipfs://) // the tokenUri **MUST NOT** point at mutable/censorable content (e.g., https://) // data from `tokenUri` takes precedent over data returned by this method From 840b8bd8a48d16c7c3f406cc0e1874325a1c0598 Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Mon, 30 May 2022 05:27:35 -0700 Subject: [PATCH 05/12] Update eip-5114.md --- EIPS/eip-5114.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index 3914812e6d46c..d83ee7734a068 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -12,20 +12,20 @@ requires: 721 --- ## Abstract -A soulbound token is a token that is bound to another ERC-721 token when it is minted, and cannot be transferred/moved after that. +A soulbound token is a token that is bound to another Non Fungible Token (NFT; e.g., a EIP-721 token) when it is minted, and cannot be transferred/moved after that. ## Specification ```solidity interface IERCXXXX { // fired anytime a new instance of this token is minted // this event **MUST NOT** be fired twice for the same `tokenId` - event Mint(uint256 indexed tokenId, address indexed erc721Token, uint256 indexed erc721TokenId); + event Mint(uint256 indexed tokenId, address indexed nftAddress, uint256 indexed nftTokenId); - // returns the ERC-721 token that owns this token. + // returns the NFT token that owns this token. // this function **MUST** throw if the token hasn't been minted yet // this function **MUST** always return the same result every time it is called after it has been minted // this function **MUST** return the same value as found in the original `Mint` event for the token - function ownerOf(uint256 index) external view returns (address erc721Token, uint256 erc721TokenId); + function ownerOf(uint256 index) external view returns (address nftAddress, uint256 nftTokenId); // returns a censorship resistant URI with details about this token collection // the metadata returned by this is merged with the metadata return by `tokenUri(uint256)` @@ -60,5 +60,7 @@ Users of tokens that claim to implement this EIP must be diligent in verifying t It should also be made clear that Soulbound tokens are not bound to a human, they are bound to a persona. A persona is any actor (which could be a group of humans) that collects multiple soulbound tokens over time to build up a collection of badges. This persona may transfer to another human, or to another group of humans, and anyone interacting with a persona should not assume that there is a single permanent immutable human behind that persona. +It is possible for a soulbound token to be bound to another soulbound token. In theory, if all tokens in the chain are created at the same time they could form a loop. Software that tries to walk such a chain should take care to have an exit strategy if a loop is detected. + ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). From 9744e0dc47fc098e63b1b98695ac8e7fb106280a Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Wed, 1 Jun 2022 01:08:01 +0800 Subject: [PATCH 06/12] Update EIPS/eip-5114.md Co-authored-by: KillariDev --- EIPS/eip-5114.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index d83ee7734a068..6fbe4e43e8621 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -53,7 +53,7 @@ Soulbound tokens are meant to be permanent badges/indicators attached to a perso The format of the data pointed to by `collectionUri()` and `tokenUri(uint256)` is intentionally left out of this standard in favor of separate standards that can be iterated on in the future. The immutability constraints are the only thing defined by this to ensure that the spirit of this token is maintained, regardless of the specifics of the data format. ## Backwards Compatibility -This is a new tokene type and is not meant to be backward compatible with any existing tokens other than using ERC-721 as souls. +This is a new token type and is not meant to be backward compatible with any existing tokens other than using ERC-721 as souls. ## Security Considerations Users of tokens that claim to implement this EIP must be diligent in verifying they actually do. A token author can create a token that, upon initial probing of the API surface, may appear to follow the rulse when in reality it doesn't. For example, the contract could allow transfers via some mechanism and simply not utilize them initially. From 8c4ef5b25e37a1081e010adeeef1d1584e99a929 Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Wed, 1 Jun 2022 01:08:46 +0800 Subject: [PATCH 07/12] Update EIPS/eip-5114.md Co-authored-by: KillariDev --- EIPS/eip-5114.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index 6fbe4e43e8621..a4a001f36dc01 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -56,7 +56,7 @@ The format of the data pointed to by `collectionUri()` and `tokenUri(uint256)` i This is a new token type and is not meant to be backward compatible with any existing tokens other than using ERC-721 as souls. ## Security Considerations -Users of tokens that claim to implement this EIP must be diligent in verifying they actually do. A token author can create a token that, upon initial probing of the API surface, may appear to follow the rulse when in reality it doesn't. For example, the contract could allow transfers via some mechanism and simply not utilize them initially. +Users of tokens that claim to implement this EIP must be diligent in verifying they actually do. A token author can create a token that, upon initial probing of the API surface, may appear to follow the rules when in reality it doesn't. For example, the contract could allow transfers via some mechanism and simply not utilize them initially. It should also be made clear that Soulbound tokens are not bound to a human, they are bound to a persona. A persona is any actor (which could be a group of humans) that collects multiple soulbound tokens over time to build up a collection of badges. This persona may transfer to another human, or to another group of humans, and anyone interacting with a persona should not assume that there is a single permanent immutable human behind that persona. From 8ce5b4cdff0ee4a7896149f0da235888ff032abb Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Wed, 1 Jun 2022 01:09:39 +0800 Subject: [PATCH 08/12] Update EIPS/eip-5114.md Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- EIPS/eip-5114.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index a4a001f36dc01..2ccddc1127589 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -12,7 +12,7 @@ requires: 721 --- ## Abstract -A soulbound token is a token that is bound to another Non Fungible Token (NFT; e.g., a EIP-721 token) when it is minted, and cannot be transferred/moved after that. +A soulbound token is a token that is bound to another Non-Fungible Token (NFT; e.g., a EIP-721 token) when it is minted, and cannot be transferred/moved after that. ## Specification ```solidity From 5ff1de05b2d1ecc7c66de3147187754e22b198a3 Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Wed, 1 Jun 2022 01:09:51 +0800 Subject: [PATCH 09/12] Update EIPS/eip-5114.md Co-authored-by: William Schwab <31592931+wschwab@users.noreply.github.com> --- EIPS/eip-5114.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index 2ccddc1127589..0d9682e5a7972 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -16,7 +16,7 @@ A soulbound token is a token that is bound to another Non-Fungible Token (NFT; e ## Specification ```solidity -interface IERCXXXX { +interface IERC5114 { // fired anytime a new instance of this token is minted // this event **MUST NOT** be fired twice for the same `tokenId` event Mint(uint256 indexed tokenId, address indexed nftAddress, uint256 indexed nftTokenId); From a5f3b67348f8aa93bde760786c31f0c13fcad5bf Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Wed, 1 Jun 2022 01:15:27 +0800 Subject: [PATCH 10/12] fixes double space after sentences Per request by @lightclient --- EIPS/eip-5114.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index 0d9682e5a7972..c5f22b703f0b9 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -48,19 +48,28 @@ interface IERC5114 { ### Immutability By requiring that tokens can never move, we both guarantee non-seperability and non-mergability among collections of soulbound tokens that are bound to a single NFT while simultaneously allowing users to aggressively cache results. ### Content Addressible URIs Required -Soulbound tokens are meant to be permanent badges/indicators attached to a persona. This means that not only can the user not transfer ownership, but the minter also cannot withdraw/transfer/change ownership as well. This includes mutating or removing any remote content as a means of censoring or manipulating specific users. +Soulbound tokens are meant to be permanent badges/indicators attached to a persona. +This means that not only can the user not transfer ownership, but the minter also cannot withdraw/transfer/change ownership as well. +This includes mutating or removing any remote content as a means of censoring or manipulating specific users. ### No Specification for tokenUri Data Format -The format of the data pointed to by `collectionUri()` and `tokenUri(uint256)` is intentionally left out of this standard in favor of separate standards that can be iterated on in the future. The immutability constraints are the only thing defined by this to ensure that the spirit of this token is maintained, regardless of the specifics of the data format. +The format of the data pointed to by `collectionUri()` and `tokenUri(uint256)` is intentionally left out of this standard in favor of separate standards that can be iterated on in the future. +The immutability constraints are the only thing defined by this to ensure that the spirit of this token is maintained, regardless of the specifics of the data format. ## Backwards Compatibility This is a new token type and is not meant to be backward compatible with any existing tokens other than using ERC-721 as souls. ## Security Considerations -Users of tokens that claim to implement this EIP must be diligent in verifying they actually do. A token author can create a token that, upon initial probing of the API surface, may appear to follow the rules when in reality it doesn't. For example, the contract could allow transfers via some mechanism and simply not utilize them initially. +Users of tokens that claim to implement this EIP must be diligent in verifying they actually do. +A token author can create a token that, upon initial probing of the API surface, may appear to follow the rules when in reality it doesn't. +For example, the contract could allow transfers via some mechanism and simply not utilize them initially. -It should also be made clear that Soulbound tokens are not bound to a human, they are bound to a persona. A persona is any actor (which could be a group of humans) that collects multiple soulbound tokens over time to build up a collection of badges. This persona may transfer to another human, or to another group of humans, and anyone interacting with a persona should not assume that there is a single permanent immutable human behind that persona. +It should also be made clear that Soulbound tokens are not bound to a human, they are bound to a persona. +A persona is any actor (which could be a group of humans) that collects multiple soulbound tokens over time to build up a collection of badges. +This persona may transfer to another human, or to another group of humans, and anyone interacting with a persona should not assume that there is a single permanent immutable human behind that persona. -It is possible for a soulbound token to be bound to another soulbound token. In theory, if all tokens in the chain are created at the same time they could form a loop. Software that tries to walk such a chain should take care to have an exit strategy if a loop is detected. +It is possible for a soulbound token to be bound to another soulbound token. +In theory, if all tokens in the chain are created at the same time they could form a loop. +Software that tries to walk such a chain should take care to have an exit strategy if a loop is detected. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md). From 90a438c50306d781a45319413b686d348ce82bfb Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Tue, 31 May 2022 23:38:43 -0700 Subject: [PATCH 11/12] Apply suggestions from code review Co-authored-by: KillariDev --- EIPS/eip-5114.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index c5f22b703f0b9..4f1c0ca3d70d1 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -31,14 +31,14 @@ interface IERC5114 { // the metadata returned by this is merged with the metadata return by `tokenUri(uint256)` // the tokenUri **MUST** be immutable and content addressable (e.g., ipfs://) // the tokenUri **MUST NOT** point at mutable/censorable content (e.g., https://) - // data from `tokenUri` takes precedent over data returned by this method + // data from `tokenUri` takes precedence over data returned by this method // any external links referenced by the content at `tokenUri` also **MUST** follow all of the above rules function collectionUri() external view returns (string tokenUri); // returns a censorship resistant URI with details about this token instance // the tokenUri **MUST** be immutable and content addressable (e.g., ipfs://) // the tokenUri **MUST NOT** point at mutable/censorable content (e.g., https://) - // data from this takes precedent over data returned by `collectionUri` + // data from this takes precedence over data returned by `collectionUri` // any external links referenced by the content at `tokenUri` also **MUST** follow all of the above rules function tokenUri(uint256 tokenId) external view returns (string tokenUri); } @@ -46,8 +46,8 @@ interface IERC5114 { ## Rationale ### Immutability -By requiring that tokens can never move, we both guarantee non-seperability and non-mergability among collections of soulbound tokens that are bound to a single NFT while simultaneously allowing users to aggressively cache results. -### Content Addressible URIs Required +By requiring that tokens can never move, we both guarantee non-separability and non-mergeability among collections of soulbound tokens that are bound to a single NFT while simultaneously allowing users to aggressively cache results. +### Content Addressable URIs Required Soulbound tokens are meant to be permanent badges/indicators attached to a persona. This means that not only can the user not transfer ownership, but the minter also cannot withdraw/transfer/change ownership as well. This includes mutating or removing any remote content as a means of censoring or manipulating specific users. @@ -56,7 +56,7 @@ The format of the data pointed to by `collectionUri()` and `tokenUri(uint256)` i The immutability constraints are the only thing defined by this to ensure that the spirit of this token is maintained, regardless of the specifics of the data format. ## Backwards Compatibility -This is a new token type and is not meant to be backward compatible with any existing tokens other than using ERC-721 as souls. +This is a new token type and is not meant to be backward compatible with any existing tokens other than existing viable souls (like EIP-721 tokens). ## Security Considerations Users of tokens that claim to implement this EIP must be diligent in verifying they actually do. From fca8a8ce60931a3261f88fc282e8ea4315b36328 Mon Sep 17 00:00:00 2001 From: Micah Zoltu Date: Fri, 3 Jun 2022 22:37:50 -0700 Subject: [PATCH 12/12] Apply suggestions from code review Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-5114.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/EIPS/eip-5114.md b/EIPS/eip-5114.md index 4f1c0ca3d70d1..c53ad3f9e632b 100644 --- a/EIPS/eip-5114.md +++ b/EIPS/eip-5114.md @@ -29,11 +29,11 @@ interface IERC5114 { // returns a censorship resistant URI with details about this token collection // the metadata returned by this is merged with the metadata return by `tokenUri(uint256)` - // the tokenUri **MUST** be immutable and content addressable (e.g., ipfs://) - // the tokenUri **MUST NOT** point at mutable/censorable content (e.g., https://) + // the collectionUri **MUST** be immutable and content addressable (e.g., ipfs://) + // the collectionUri **MUST NOT** point at mutable/censorable content (e.g., https://) // data from `tokenUri` takes precedence over data returned by this method - // any external links referenced by the content at `tokenUri` also **MUST** follow all of the above rules - function collectionUri() external view returns (string tokenUri); + // any external links referenced by the content at `collectionUri` also **MUST** follow all of the above rules + function collectionUri() external view returns (string collectionUri); // returns a censorship resistant URI with details about this token instance // the tokenUri **MUST** be immutable and content addressable (e.g., ipfs://) @@ -63,7 +63,7 @@ Users of tokens that claim to implement this EIP must be diligent in verifying t A token author can create a token that, upon initial probing of the API surface, may appear to follow the rules when in reality it doesn't. For example, the contract could allow transfers via some mechanism and simply not utilize them initially. -It should also be made clear that Soulbound tokens are not bound to a human, they are bound to a persona. +It should also be made clear that soulbound tokens are not bound to a human, they are bound to a persona. A persona is any actor (which could be a group of humans) that collects multiple soulbound tokens over time to build up a collection of badges. This persona may transfer to another human, or to another group of humans, and anyone interacting with a persona should not assume that there is a single permanent immutable human behind that persona.