Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERC1238: Non-transferrable Non-Fungible Tokens (NTT) #1238

Closed
nicola opened this issue Jul 20, 2018 · 63 comments
Closed

ERC1238: Non-transferrable Non-Fungible Tokens (NTT) #1238

nicola opened this issue Jul 20, 2018 · 63 comments

Comments

@nicola
Copy link

nicola commented Jul 20, 2018

eip: 1238
title: Non-transferrable Non-Fungible Tokens (badges)
author: Nicola Greco (and future others)
status: WIP
category: ERC
created: 2018-07-20

Non-transferable tokens

Simple Summary

A badge is a token that once assigned it cannot be transferred. Badges can be accumulated through time and put at stake. Simply speaking, badges are statements about a public key, they can be quantitative (e.g. reputation, experience) or qualitative (badges, titles).

Abstract

The Non-transferrable token standard defines a set of standard APIs allowing the identification of statements (called badges) attributed to a public key, such that different dapps and smart contract can use to filter users or to provide user with different badges different experiences. More importantly, this standard defines a way for which users can put their badges at stake. Badges cannot be transferred but can be lost (after staking) or can expire.

Motivation

The inspiration for designing badges comes from a conversation with Andrew Miller. The idea is to have a token that once assigned it cannot be transferred (like reputation) and that it can be used by websites, or contracts to make me perform some actions. For example, if a user accumulates paper submissions at conferences, then they can use their paper badges to request grants. It's important that they can never share these badges.

This is the equivalent of a variety of other use cases

  • Accumulating badges: degrees from academic institutions, paper publications for conferences, badges that allow for access in a building or in a special chat.
  • Experience points: points accumulated in a game, points accumulated by being honest in a decentralized system for some time
  • Statements: more broadly, any statement that is issued or signed by a contract, a dao, a single user that requires to be on-chain
  • Subscription: badges can represent the validity of a paid subscription

Requirements for specification

  • Quantity: a badge can have the form of 1-many, meaning that a badge can represent a single value (Degree from CS, 1), or can a quantity (Experience in Fortnite, 2000)
  • Stake: it should be simple to put at stake contingent on a smart contract execution (however, it is understandable that this could be done by a different standard)
  • Backwards compatibility: This standard should have similar apis to existing standards (e.g. ERC: Token standard #20, ERC: Non-fungible Token Standard #721), I makes sense for an NFT viewer to also view badges
  • Off-chain tokens: This specification should work also for tokens that are not issued on chain (say by a third party signer) and can be presented on chain only when necessary (it's understandable that this is an edge case and could fall off the spec, but it's an interesting one!)

Next steps

There are two main steps here:

  • Specification
  • Implementation

However, I will have very little time to actually bring this to life. It would be awesome if any contributor here feels strong and empowered to take over this standard and make this their own. I started this while thinking on a fun project for academia (namely called research coin), maybe someone wants to help there!

@nicola nicola changed the title ERC1231: Non-transferrable tokens (badges) ERC1238: Non-transferrable tokens (badges) Jul 20, 2018
@Arachnid
Copy link
Contributor

I like the idea of badges, but I think it's a mistake to tie them to a single address. Over time people will have multiple accounts, and making them non-transferrable will discourage people from switching to a more secure account (eg, from a software wallet to a hardware one).

@nicola
Copy link
Author

nicola commented Jul 20, 2018

I guess you can always ask the issuer to re-issue a new badge, or maybe you can only transfer a badge if the issuer agrees on the transfering. The problem is with decentralized issuing, this might be an issue!

@adibas03
Copy link

adibas03 commented Jul 22, 2018

I think a way to escape the address restriction is to utilize the proxy implementation #121 or identity from #725 such that the proxy/identity has the badge and such the owner can have access with any of the owned addresses

@chiro-hiro
Copy link
Contributor

@nicola will the reputation be decayed overtime?

The same thing happens in real world :)

@Arachnid
Copy link
Contributor

@adibas03 That demonstrates how pointless preventing transfers would be - it's easily evaded, and so just makes life more difficult for users.

@nicola
Copy link
Author

nicola commented Jul 23, 2018

@chiro-hiro it would be up to you, how you implement it

@Arachnid I agree and disagree, the identity would be an ID where you can decide the set of keys that own that ID, you can't transfer badges across IDs.. For example, when playing in a game, you only have one ID per player and you only have some experience. In other words, I believe there is something useful here.

note: re-issuing is still a valid option for some usecases

@adibas03
Copy link

adibas03 commented Jul 23, 2018

@Arachnid I see your point about the non-transferable attribute. Similar to game credits, which are not natively transferrable, but the accounts with the credits and repuation can be sold. So, the proxy/Identity accounts can be transferred in a way.
@nicola I think @Arachnid has a point here.
Also, could the badges be an example of a claim as described in #735

@MicahZoltu
Copy link
Contributor

There is a big difference between transferring individual badges and transferring all badges associated with a key. I think there is noue in allowing users to transfer all of their badges to a new key, while also preventing individual badges from being transferred away.

One can think of the set of badges as identifying a user, and you cannot split the user into parts and have it be the same user, but you can transfer a user to a new private key.

@vongohren
Copy link

What differences do you see between badges and claims?
Ref: https://medium.com/uport/erc1056-erc780-an-open-identity-and-claims-protocol-for-ethereum-aef7207bc744

Both #735 and uPort uses the wording of claims.

@nicola
Copy link
Author

nicola commented Jul 26, 2018

#735 looks very similar, if not identical to that, I will reach out to them.

@PhABC
Copy link
Contributor

PhABC commented Jul 27, 2018

I worked on some "badge" token stuff to quantify participation events for fun and also opted for "transfer all or none scheme" as @MicahZoltu proposes, which I think is good enough for the intent here.

@jcksncllwy
Copy link

@vongohren A significant difference between #735 claims and #1238 badges is information ownership. In #735 the Claim Holder owns any claims made about themselves. The problem with this is that there is no way for a Claim Issuer to revoke or alter a claim once it has been issued. While #735 does specify a removeClaim method, a malicious implementation could simply ignore that method call, because they own the claim.

Imagine that SafeEmploy™, a background checking company, issues a claim about Timmy. The claim states that Timmy has never been convicted of any felonies. Timmy makes some bad decisions, and now that claim is no longer true. SafeEmploy™ executes removeClaim, but Timmy's #735 contract just ignores it, because Timmy wants to stay employed (and is crypto-clever).

#1238 badges do not have this problem. Ownership of a badge/claim is entirely determined by the contract issuing the badges, not the one receiving them. The issuer is free to remove or change those badges as they see fit.

@conejoninja
Copy link

@jcksncllwy In #725 (along with #735) The claim issuer could remove the key (from their own identity) that signed the claim to revoke it.

@OFRBG
Copy link

OFRBG commented Aug 13, 2018

Reputation system are likely to be abused. Cutting the explanation and straight to the example:

A major org around Ethereum decides to screen users. The screening process may only be performed by said org, since they set the rules for their own DApp. Being the first mover with a household name.

Since Ethereum doesn't have truly private methods and attributes, other DApp groups can easily read the badges other users have. If the major org with first mover advantage creates its own version of crypto-TSA, other groups will simply save time and resources, piggybacking on what's available.

If the problem isn't already blatantly obvious, think about the reputation bottleneck this causes: the major org or orgs that work as a crypto-TSA become gatekeepers for the whole system. We know from history that some things we do aren't the best, but they stuck because they were the most comfortable. When going from a reputation-less system into a reputation-based system, whatever comes first is most likely to stay.

On a trustless network every address should be no different from any other. I think a measured reputation system goes against what crypto should be. In other words, creating an issued-reputation ERC is opening Pandora's Box.

@cbruguera
Copy link

I think this is an interesting idea. It's definitely related to the concept of claims, but I can see an interoperability advantage in defining the behavior of these "claims" in a contract specific to the claim "type" (i.e. badge), instead of residing in the claim holder or issuer contracts (similar to how ERC20 and ERC721 work).

With regard to not limiting badge ownership to a single address, that's where we start getting into identity territory, which is not a trivial one. I came across this proposal recently, perhaps you guys might be interested in having a look at it and it would be good to know your feedback on the matter.

One question about defining this as a standard: should badge issuers be able to arbitrarily revoke the badge? Or would this stay outside the scope of a standard and be more a matter of particular implementation?

@adibas03
Copy link

@OFRBG You are right about the danger of Reputation, but as you mentioned, the implementation plays a big role.All or null transfer-ability as suggested by @MicahZoltu still seems the best possible option.
Also, the two main preferable implementation I believe are (I am using claim t refer to both claims #735 and badges #1238),

  • Claim registry contract which allows contract owner create claims on address which can be approved or rejected by the address owner. The state of the contract concerning the claim can be regarded as final, as the contract gets more approved claimed, it reputation increases, and that is when things can get interesting
  • Claimant makes a claim on an address, which is approved by the address by publishing the claim identifier (needs a standard). The claimant can at any time withdraw the claim and the address can at any time have the claim identifier information unpublished, thereby voiding the claim. In this case, both Claimant (contract) and address (Identity contract ERC: Proxy Account #725 ) both have to publish the same information to be considered approved- This is a whole lot more complicated, but I think quenches mot of the worries attached to the security concerns.

@jahowle
Copy link

jahowle commented Oct 26, 2018

Full Disclosure: I work at www.uport.me

@nicola I think the most important thought in your original posting is this

Off-chain tokens: This specification should work also for tokens that are not issued on chain (say by a third party signer) and can be presented on chain only when necessary (it's understandable that this is an edge case and could fall off the spec, but it's an interesting one!)

Why put reputation claims on-chain at all?

My assumption is that it reduces the friction between the party consuming the reputation and the party with the reputation, but that can potentially be solved at the UX/application level through easy selective, progressive, and active disclosure.

I worry about the privacy of users in any implementation of an on-chain claims registry.

I'd like to hear your's or anyone's argument for on-chain claims over off-chain claims.

@snaketh4x0r
Copy link

snaketh4x0r commented Mar 5, 2019

nice eip @nicola
I just got some free time from my busy college so I decided to contribute to decentralize web.
so here is example code with non transferable functionality implemented.

Badge is NON transferable token issued by owner to a particular identity.

badges are issued only once to new identities.
to issue new badges new contracts have to be deployed.
there can be a new function introduced to remove a identity from transfer restriction so it can be issued more badge tokens(which is of no use) but then it will have drawbacks as described in second way further below.

There were two ways to implement it,

first by preventing transfer for each identity which uses lot of gas as each identity is stored on blockchain.
secondly by freezing transfer function of contract,its gas efficient but it had few drawbacks
consider owner unfreezed transfer to issue new badge token for particular new identity,during this time any existing token holder could transfer token,onlyOwner modifier on transfer is of no use as owner would be able to transfer a token between identities hence owner can be bribed by token holders to transfer their tokens to another token holder but we have to prevent that.
so first way is best way plus owner can set his address as target and so no one will be able transfer any token in future not even owner hence no new token issued.

owner here can be
single address or multi-sig address contract controlled by single individual or group->centralized
DAO->decentralized
public by anyone->truly decentralized

Repution system is not implemented as secure,safe reputation system on chain is not proposed yet,all current iterations of reputation system on chain are exploitable,defining it into a standard will be like making a bug a standard.

off chain tokens can be created thanks to create2 but it would be better to use it in universal login.
so a proxy identity contract will be created for a user to which owner will issue a badge or non transferable token and it will be controlled by set of allowed keys.

I disagree with @Arachnid that Non transfer function of token will discourage people from switching to more secure wallet as a solution like universal login can be used and so there will be no need to switch wallets as token will be issued to secure smart contract wallet controlled by keys selected by user.

Applications

1.can be used to issue badges to identity
2.can be used for voting tokens as votes between user cannot be transferred among other user but sent to contract for voting.
3.to give Credentials to identities like driver license or educational certificate from academic institutions,identity holding them won't be able to transfer their credentials like license or certificates to others.
4.still to be discovered.....

->code starts here

// ERC Token Standard #20 Interface extended to Non transferable token(Badge) standard
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
// ----------------------------------------------------------------------------
/*
contract ERC20Interface {
    function totalSupply() public view returns (uint);
    function balanceOf(address tokenOwner) public view returns (uint balance);
    function allowance(address tokenOwner, address spender) public view returns (uint remaining);
    function freezeAccount(address target,bool freeze) public returns (bool success);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
    event NonTransferable(address target, bool frozen);

*/

pragma solidity ^0.5.0;

// ----------------------------------------------------------------------------
// 'FIXED' 'Example Fixed Supply Non Transferable Token' token contract
//
// Symbol      : FIXED
// Name        : Example Fixed Supply Non Transferable Token
// Total supply: 1,000,000.000000000000000000
// Decimals    : 18
//
// Enjoy.
//
// ERC-20 standard taken from (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. The MIT Licence.
//thanks for your contribution to community
//extended for non transferable token by Snaketh4xor
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
// Safe maths
// ----------------------------------------------------------------------------
library SafeMath {
    function add(uint a, uint b) internal pure returns (uint c) {
        c = a + b;
        require(c >= a);
    }
    function sub(uint a, uint b) internal pure returns (uint c) {
        require(b <= a);
        c = a - b;
    }
    function mul(uint a, uint b) internal pure returns (uint c) {
        c = a * b;
        require(a == 0 || c / a == b);
    }
    function div(uint a, uint b) internal pure returns (uint c) {
        require(b > 0);
        c = a / b;
    }
}


// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
// ----------------------------------------------------------------------------
contract ERC20Interface {
    function totalSupply() public view returns (uint);
    function balanceOf(address tokenOwner) public view returns (uint balance);
    function allowance(address tokenOwner, address spender) public view returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}


// ----------------------------------------------------------------------------
// Contract function to receive approval and execute function in one call
//
// Borrowed from MiniMeToken
// ----------------------------------------------------------------------------
contract ApproveAndCallFallBack {
    function receiveApproval(address from, uint256 tokens, address token, bytes memory data) public;
}


// ----------------------------------------------------------------------------
// Owned contract
// ----------------------------------------------------------------------------
contract Owned {
    address public owner;
    address public newOwner;

    event OwnershipTransferred(address indexed _from, address indexed _to);

    constructor() public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    function transferOwnership(address _newOwner) public onlyOwner {
        newOwner = _newOwner;
    }
    function acceptOwnership() public {
        require(msg.sender == newOwner);
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
        newOwner = address(0);
    }
}


// ----------------------------------------------------------------------------
// ERC20 Token, with the addition of symbol, name and decimals and a
// fixed supply extended to Non transferable token 
// ----------------------------------------------------------------------------
contract FixedSupplyToken is ERC20Interface, Owned {
    using SafeMath for uint;

    string public symbol;
    string public  name;
    uint8 public decimals;
    uint _totalSupply;

    mapping(address => uint) balances;
    mapping(address => mapping(address => uint)) allowed;
    mapping(address => bool) public frozenAccount;
    
    event NonTransferable(address target, bool frozen);

    // ------------------------------------------------------------------------
    // Constructor
    // ------------------------------------------------------------------------
    constructor() public {
        symbol = "FIXED";
        name = "Example Fixed Supply Token";
        decimals = 18;
        _totalSupply = 1000000 * 10**uint(decimals);
        balances[owner] = _totalSupply;
        emit Transfer(address(0), owner, _totalSupply);
    }


    // ------------------------------------------------------------------------
    // Total supply
    // ------------------------------------------------------------------------
    function totalSupply() public view returns (uint) {
        return _totalSupply.sub(balances[address(0)]);
    }


    // ------------------------------------------------------------------------
    // Get the token balance for account `tokenOwner`
    // ------------------------------------------------------------------------
    function balanceOf(address tokenOwner) public view returns (uint balance) {
        return balances[tokenOwner];
    }

    //stops transfer of tokens for identity.
    function freezeAccount(address target, bool freeze) onlyOwner public returns (bool success) {
        frozenAccount[target] = freeze;
        emit NonTransferable(target, freeze);
        return true;
    }
    // ------------------------------------------------------------------------
    // Transfer the balance from token owner's account to `to` account
    // - Owner's account must have sufficient balance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transfer(address to, uint tokens) onlyOwner public returns (bool success) {
        require(!frozenAccount[to]);
        require(!frozenAccount[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(tokens);
        balances[to] = balances[to].add(tokens);
        freezeAccount(to, true);
        emit Transfer(msg.sender, to, tokens);
        return true;
    }


    // ------------------------------------------------------------------------
    // Token owner can approve for `spender` to transferFrom(...) `tokens`
    // from the token owner's account
    //
    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
    // recommends that there are no checks for the approval double-spend attack
    // as this should be implemented in user interfaces
    // ------------------------------------------------------------------------
    function approve(address spender, uint tokens) onlyOwner public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        return true;
    }


    // ------------------------------------------------------------------------
    // Transfer `tokens` from the `from` account to the `to` account
    //
    // The calling account must already have sufficient tokens approve(...)-d
    // for spending from the `from` account and
    // - From account must have sufficient balance to transfer
    // - Spender must have sufficient allowance to transfer
    // - 0 value transfers are allowed
    // ------------------------------------------------------------------------
    function transferFrom(address from, address to, uint tokens) onlyOwner public returns (bool success) {
        require(!frozenAccount[to]);
        require(!frozenAccount[from]);
        balances[from] = balances[from].sub(tokens);
        allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
        balances[to] = balances[to].add(tokens);
        freezeAccount(to, true);
        emit Transfer(from, to, tokens);
        return true;
    }

    // ------------------------------------------------------------------------
    // Returns the amount of tokens approved by the owner that can be
    // transferred to the spender's account
    // ------------------------------------------------------------------------
    function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
        return allowed[tokenOwner][spender];
    }


    // ------------------------------------------------------------------------
    // Token owner can approve for `spender` to transferFrom(...) `tokens`
    // from the token owner's account. The `spender` contract function
    // `receiveApproval(...)` is then executed
    // ------------------------------------------------------------------------
    function approveAndCall(address spender, uint tokens, bytes memory data) onlyOwner public returns (bool success) {
        allowed[msg.sender][spender] = tokens;
        emit Approval(msg.sender, spender, tokens);
        ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, address(this), data);
        return true;
    }


    // ------------------------------------------------------------------------
    // Don't accept ETH
    // ------------------------------------------------------------------------
    function () external payable {
        revert();
    }


    // ------------------------------------------------------------------------
    // Owner can transfer out any accidentally sent ERC20 tokens
    // ------------------------------------------------------------------------
    function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
        return ERC20Interface(tokenAddress).transfer(owner, tokens);
    }
}

@winnal
Copy link

winnal commented Apr 5, 2019

I was thinking of a use-case for a non-transferable token for the purposes of a founders token, where tokens are bound to the user account, and the user can use the tokens for voting, private access to the platform (like beta testing) and spending/burning to redeem a benefit, but cannot trade or transfer the token, which would make a founders token sale (FTO) exempt from securities regulation as the token cannot be traded, yet would enable there to be a development fund through a token sale.

The concept comes from many traditional industries that sell a product before it’s been developed, like a founder’s or limited edition and preorder. They are able to do this because these sales cannot be transferred and is essentially a purchase rather than an investment. And in the case of non-transferable tokens with utility, you can effectively conduct a sale of tokens as an exclusive feature or benefits that cannot be traded therefore not considered an investment.

Creating such a token will have tremendous potential for ICOs (designated as a FTO) to be conducted for development funding that won’t be deemed a security. It could completely change the way startups get seed funding without the limitations of an investment deal.

@xuhcc
Copy link

xuhcc commented Feb 27, 2020

I think that it is sufficient to provide a single method that returns boolean value indicating transferrability of a token. All other details should be left to implementers. Such interface will be compatible with ERC20, ERC721, ERC1155 and other token standards.

Here's an example:

contract ERC1238 is ERC165 {

    bool internal _transfersEnabled;

    /*
     *     bytes4(keccak256('transfersEnabled()')) == 0xbef97c87
     */
    bytes4 private constant _INTERFACE_ID_ERC1238 = 0xbef97c87;

    constructor () public {
        _registerInterface(_INTERFACE_ID_ERC1238);
    }
    
    function transfersEnabled() external view returns (bool) {
        return _transfersEnabled;
    }
}

The name trasfersEnabled is borrowed from MiniMe token contract. It is also used by Aragon to designate non-transerrable reputation and membership tokens in DAOs.

Transferrability of ERC1238 token can change depending on some condition, so it allows complex logic like the "all or none" scheme described earlier in this thread.

@rosspeili
Copy link

I am not sure how viable this contract can be, but having in mind potential future use-cases, I assume it should be abuse-proof. For example, We create a biometric web3 ID by completing a DNA sequencing, we upload this data to a bioinformatics related blockchain like Zenome, ARNA, or Encrypgen. The respective DLT platform could mint NTTs based on a KYC procedure that includes the genomic data. This NTT could be used as a web3 ID, and it can also be used to retrieve a wallet in case of loss of all recovery methods including private key and seed phrase. Eg. I lost my web3 wallet that has a biometric NTT, I perform a new test or request my test from the lab, or blockchain that created the initial contract using real-time KYC. Proving our new or retrieved DNA test, we could retrieve our wallet, again, considering the ERC is secure and truly nontransferable. That for, if once I mint my own biometric ID and manage to transfer it to your wallet, I could easily create a second test to claim access to your wallet that will basically indicate it bears my DNA. NTT must be obsolete. It's nice to have NTTs with expiration data, but biometric IDs could be only one time mint, one time transfer, nonfungible, and not transferable tokens. That's one of the most exciting ERCs and its a shame DeFi dudes are not paying attention.

@Genobank
Copy link

@rosspeili please review our peer reviewed article. Happy to collaborate.

"Privacy Laws, Genomic data and Non-fungible-tokens"
https://jbba.scholasticahq.com/article/13164.pdf

1 similar comment
@Genobank
Copy link

@rosspeili please review our peer reviewed article. Happy to collaborate.

"Privacy Laws, Genomic data and Non-fungible-tokens"
https://jbba.scholasticahq.com/article/13164.pdf

@nicola nicola changed the title ERC1238: Non-transferrable tokens (badges) ERC1238: Non-transferrable tokens Sep 22, 2020
@ra-phael
Copy link

ra-phael commented Feb 13, 2022

What do you see as different use cases for escrow vs burnable approach to staking?

Currently in the repo, ERC1238Holdable introduces a distinction between which address owns some tokens and which address holds them (could be a smart contract where there are held in escrow). An address can only burn tokens up to the amount they hold. ERC1238Stakable is a bit more radical as it lets a token owner grant some "burn" allowances to some addresses which then have the ability to give them up.
One use case would be taking a loan and using your badge tokens as collateral but there are probably others. I think both approaches could be used. The first one is easier to reason about when burning tokens but it doesn't let an issuer burn/revoke any token that they minted (which can be a requirement in some cases). With the second one the question is what happens to allowances when tokens are burnt? Either they could be decreased proportionally or left untouched.

@vongohren I totally agree with you. Even though diplomas, national ids, etc... are brought up as use cases for badges, I don't view this standard as an invitation to store personally identifiable information publicly on-chain and strongly advise against it, because there's no way to undo it. VCs have this advantage that they can be stored privately but are more difficult to use in smart contracts than on-chain tokens.

A Badge Token standard will have an interface that answers the following questions:


  • can it only be minted by the authority (contract owner)?

@ccarnino I would leave that out from the standard; just like how ERC20 or ERC721 implementations provide internal functions and let developers define their own authorization logic for minting (could be the contract owner, a DAO, a multi-sig, a pre-approved list of addresses...).

  • NFTs transferrable only to other wallets I own

How would you make sure they're owned by the same person?
I think it's simpler to not allow transfers between addresses altogether and let issuers burn + re-issue to another address if need be.

@nicola
Copy link
Author

nicola commented Feb 13, 2022

Leaving this as a note based on conversations that I had in the past few days.

Things that need to be addressed:

  • Find a mechanism to get rid of NTT from a wallet (e.g. imagine someone airdropping unwanted tokens)
  • Find a mechanism for tokens to be put at stake - however if lost they become burned instead of transferred.
    • I expect that this will have to do with the NTT registry implementation rather than the NTT standard
    • The use case we are targeting are putting "reputation" at risk type of dynamics.

@zhongeric
Copy link

zhongeric commented Feb 14, 2022

In practice, I think that buying an externally owner account for its badges is not that attractive. In the case of a Web 2 account being sold, the first thing the buyer does is changing the email and password associated to it. However the private key associated with an EOA can’t be changed obviously.

@ra-phael This parallel you drew to web 2 was really great, and I think we should expand on this further. I also do not think NTTs should offer any guarantee of user-address matching, but rather leave it up to services to corroborate them with their own off-chain data to verify a user.

On the topic of transferability (especially between wallets of the same user), looking to web2 implementations of this might be our best bet. For example, if Alice completes an IT certification course under the email A, for short, a certificate is now tied to that email address in the issuer's database. Now, if Alice decides to switch to a more secure email, B, she would have a few options for getting her hard earned certificate to be owned by her new account:

  1. Request a new certificate from the issuer, proving she previously received it using her account under A. This would lead to a burning of the certificate on account A. The issuer can use any off-chain PII they collected to verify that Alice is the owner of both accounts (kyc, etc.)
  2. Stop using her old account under A and redo the course to earn another certificate under B.

Alice expects that she will be able to transfer her previous certificates to her new account, but understands that she has to prove her identity beforehand to the issuer. If she doesn't want to, option 2 is less ideal but works. How can we correlate this with NTTs?

A proposal that implements the following would be interesting to explore:

  • NTTs cannot be bought.
  • NTTs cannot be transferred after mint.
  • NTTs can be burned by their current holders.
  • NTTs can be burned by their issuers.

Assuming that "account flipping" is a non-issue due to the immutability of private keys, users can still transfer NTTs between their accounts by verifying ownership with its issuer. Issuers are also incentivized to prevent against sybil attacks since they could severely weaken the credibility of their issued NTTs (ex. allowing users to print other people's concert tickets). They can also choose to implement varying levels of verification depending on their needs since the NTTs do not establish any standard (ownership can mean having control of the original email, or it can use Government IDs). Users can choose to share as much as they want with issuers, and they can remove unwanted NTTs from their account (malicious airdrops, attempts to dox, etc.).

Curious to hear thoughts!

@csuwildcat
Copy link

Are folks here aware of Decentralized Identifiers and Verifiable Credentials? I ask because those are existing international standards that already provide this functionality. You can use these tools today via countless implementations and libraries available in all major languages across all platforms. The neat part is they are faster, cheaper, and more efficient for these use cases.

@vongohren
Copy link

@csuwildcat thank for stepping in and showing support for that, I have been linking to that world pretty heavily in my comments above, but its difficult to look out of the ethereum world

@wwwmaster1
Copy link

There is some great thought here, and in the DID/VC world that can be leveraged as @vongohren has been saying, but I believe there is an assumption that credentials must come from an authority - but that's not how it works IRL. Credentials come from individuals (I tell you I went to "Harvard") but the verification comes from an authority (Harvard's Records). There is obviously incentive for me to lie and there may be no cost to do so, but anyone should be able to validate it with some effort (a bit of gas), and it may not be worth ruining my reputation to do so.

The problem I see with DID and SSI solutions these days is that there is always some third party that runs the show, or requires a special wallet, so it's not really decentralized and trustless. Why can't I create my own identity credentials (true or imaginary) and store them (or identifiers to IPFS files) in my metamask wallet, and allow them to be verified (or not) by some authority (like SSL). In fact, some of that data may even be encrypted (private medical records), and require the certification from authority in order to be decrypted.

@vongohren
Copy link

So what I read here have some troubles to me, when it comes to understanding of the SSI/DID/VC space.
There dont have to be any authority, just an issuer, can be a person. The problem you sit with is just discovery and do I trust this issuer(person), and how do one make that trust.

This is no different from a random ethereum address giving a token.

When it comes to software consuming this, you say it is a third party running the show, is not Metamask a third party running the show? They have software you install, and probably run all your transactions through Infura, which lets them decide what goes through and not? So I dont see the difference?

There is also no problem for Metamask to expand to controlling this type of software inside their wallet and send and exchange. We do see that some wallets of the DID/SSI/VC space also want to handle crypto.

Your vision is ripe to be developed, and I know there are people trying out DIDs on IPFS, encrypted storage on different mediums. So everything you talk about is possible.

There is no reason DID/SSI/VC space, should be more centralized than metamask, but Microsoft f.ex, are afraid to build it that way. But others can!

@csuwildcat
Copy link

There is some great thought here, and in the DID/VC world that can be leveraged as @vongohren has been saying, but I believe there is an assumption that credentials must come from an authority - but that's not how it works IRL. Credentials come from individuals (I tell you I went to "Harvard") but the verification comes from an authority (Harvard's Records). There is obviously incentive for me to lie and there may be no cost to do so, but anyone should be able to validate it with some effort (a bit of gas), and it may not be worth ruining my reputation to do so.

The problem I see with DID and SSI solutions these days is that there is always some third party that runs the show, or requires a special wallet, so it's not really decentralized and trustless. Why can't I create my own identity credentials (true or imaginary) and store them (or identifiers to IPFS files) in my metamask wallet, and allow them to be verified (or not) by some authority (like SSL). In fact, some of that data may even be encrypted (private medical records), and require the certification from authority in order to be decrypted.

@wwwmaster1 what you said here belies a fundamental misunderstanding of DIDs and VCs. Verifiable Credentials can be issued by any DID (or group) to another DID, which could be a company or organization to an individual, any individual to another individual, an individual to a machine, etc. The notion that DIDs and VCs are somehow only for authorities like governments, have any binding to centralized infra, and are not decentralized is just flat out false - seriously, that's not true by any stretch of the imagination. Just because a DMV is a relatively centralized org that issues driver's licenses that people will recognize doesn't mean your DID, their DID, or Verifiable Credentials are a centralized system. You can use these decentralized components any way you want, just like some government could use a public blockchain address/contract to facilitate centralized activities that it codifies.

I would really encourage you to dig in deeper, because the risk here is that folks are going to do a ton of work recreating a slower, less efficient, more expensive version of a decentralized system that already exists, backed by international standards that are already being adopted.

@zhongeric
Copy link

Why must we correlate NTTs with implementations of self-sovereign identity? It seems like we're trying to appropriate the NFT spec for a use case that it's not really meant for. The only link I see is the ability to interact with media, which could be personal information uploaded on-chain, which the consensus is strongly against. DID / VC implementations can be implemented in other fashions: ERC725, etc.

I no longer believe in the identity use case I previously outlined for NTTs in this thread, but I'm still an advocate for a simplistic standard: one that holds strict invariants preventing transferability (even in the edge case of wallets owned by the same user) and allowing both the issuing contract and owner of the NTT to arbitrarily burn them. These can exist independently of sovereign identity implementations.

@TimDaub
Copy link
Contributor

TimDaub commented Apr 1, 2022

I have just added my proposal for how ERC1238 could be implemented as a

@RetroWorld415
Copy link

How can I use the soulbound token or the concept of Soulbound? I want to creatively use it for rewarding people for contributing to the project. Where can I get a test code or code for it? I would like to experiment with it.

@MicahZoltu
Copy link
Contributor

There is some discussion about this over at Ethereum Magicians: https://ethereum-magicians.org/t/eip-4973-account-bound-tokens

There is no standard yet though.

@AdedamolaXL
Copy link

Can NTT be applied to encrypting data/media such that only those in possession of the token can view it ?

@ra-phael
Copy link

ra-phael commented Jun 4, 2022

@AdedamolaXL Yes, this is possible using Lit Protocol for example.

@kamilk91
Copy link

kamilk91 commented Jun 8, 2022

Guys, can you explain me one thing?

So, lets make a story.:

I have an account on forum "Ethereum is cool forum"
Im earning experience points and it for example gives me some roles, or idk, colors of nick

Forum's contract needs to send me just 1x NTT and its updating it with experience?
Or im receiving nev ntt when im gaining 1exp point
or maybe there is some standalone mechanizm of experience, that gives me NTT depends on exp points level?

@MicahZoltu
Copy link
Contributor

Closing this issue for housekeeping purposes. People are welcome to continue discussing in this thread, but for additional visibility an EIP should be created or the conversation should be migrated to https://ethereum-magicians.org/

@maprob
Copy link

maprob commented Aug 28, 2022

cant you just add a require statement in the transfer function

@lucazffz
Copy link

lucazffz commented Mar 4, 2023

If the standard requires implementers to allow holders to burn their tokens, why is a burn function not included in the specification interface?

@Pandapip1
Copy link
Member

This is not actually a standard. If @nicola or would like to actually make this a standard, I would be willing to help. However, there are already many existing EIPs that do this:

https://eips.ethereum.org/EIPS/eip-5192
https://eips.ethereum.org/EIPS/eip-5484
https://eips.ethereum.org/EIPS/eip-5114
https://eips.ethereum.org/EIPS/eip-5516
https://eips.ethereum.org/EIPS/eip-5633
https://eips.ethereum.org/EIPS/eip-5727
https://eips.ethereum.org/EIPS/eip-6454

@ethereum ethereum locked and limited conversation to collaborators Mar 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests