EIP-4974: Fungible Non-tradable Tokens, or EXP

My previous message focuses on naming more than functionality. Are you suggesting that the standard should not assume an operator can mint tokens?

This is a reasonable consideration. For instance, an implementation might allow EXP only to be transferred from other EXP contracts. The argument can extend to a burn function as well.

Maybe transfer is all that’s needed in a standard–what’s critical is that only the operator can use such a function.

This exactly! mint and burn are probably going to be fairly unique per implementation of this standard. I think you can likely get by with the transfer events, and a balance getter. Do keep in mind that I’ve only taken a cursory view of the standard, and I might entirely be wrong!

1 Like

Keeping only a privileged transfer function would definitely make this standard more general-purpose, creating an “issuer-only” controllable ERC721 standard.

Then the EXP nomenclature can be dropped from this standard, just leaving it as “Non-tradable NFTs”, as this can easily be adopted to serve other use cases besides EXP: POAPs, loyalty / community cards, etc…

1 Like

Agreed that keeping the privileged transfer function is a good option.

Non-tradable NFTs are a great concept, but I think it’s important to retain fungibility in this standard. Unique metadata for each token would actually inhibit EXP-like use cases.

Proposals I know of for non-fungible and non-tradable token standards: EIP-4671 and EIP-1238. Both are optimizing for credentials or badges, which are very different use cases from EXP.

After further discussion Magicians and others, I’ve come to several conclusions about the participation and transfer nomenclature and functionality. I propose the following solutions to these issues for EIP-4974.

Participation instead of Approval

In common parlance across the blockchain ecosystem today, approval tends to refer to approval for trading. EXP tokens are non-tradable. Further, three particular differences from existing standards justify the need for a new concept:

  1. Airdrops do not require approval in many standards today. EIP-4974 requires address to opt-in before receiving tokens.
  2. In standards such as ERC-721, it is required that setApprovalForAll “MUST allow multiple operators per owner.” EIP-4974 requires that only one operating address has control over a contracts token at any time.
  3. Many standards require complicated acceptance mechanisms to ensure the propriety of trades. As EIP-4974 does not allow trading, setting a single participation is sufficient.

In this case, we can use the following function to control how non-operating wallets engage with EXP contracts.

/// @notice Activate or deactivate participation. CALLER IS RESPONSIBLE TO
/// @dev MUST throw unless `msg.sender` is `participant`.
///  MUST throw if `participant` is `operator` or zero address.
///  MUST emit a `Participation` event for status changes.
/// @param _participant Address opting in or out of participation.
/// @param _participation Participation status of _participant.
function setParticipation(address _participant, bool _participation) external;

One transfer function instead of many component ones

We should not assume how mints or burns occur, or even if they occur. Those decisions are not core to the functionality of the standard, and may be unique across implementations. What makes EIP-4974 unique in terms of transfers is that only the operator can conduct transfers. Secondly, using only a transfer function also allows for clean alignment with other standards’ transfer functions, such as those of ERC-20 and ERC-721.

/// @notice Transfer EXP from one address to a participating address.
/// @dev MUST throw unless `msg.sender` is `operator`.
///  MUST throw unless `to` address is participating.
///  MUST throw if `to` and `from` are the same address.
///  MUST emit a Transfer event with each successful call.
///  SHOULD throw if `amount` is zero.
///  MAY allow minting from zero address, burning to the zero address, 
///  transferring between accounts, and transferring between contracts.
///  MAY limit interaction with non-participating `from` addresses.
/// @param _from Address from which to transfer EXP tokens.
/// @param _to Address to which EXP tokens at `from` address will transfer.
/// @param _amount Total EXP tokens to reallocate.
function transfer(address _from, address _to, uint256 _amount) external;
1 Like

Got it, I missed the fact that this would be for fungible tokens. Are there other use cases for fungible non-tradable tokens besides EXP? Still iffy on whether or not EXP should be explicitly defined in the EIP name.

New _transfer function looks great though!

1 Like

I agree with @fulldecent , a token that cannot be transferred is not a token imho. The function transfer is the very essence of tokens. I’d rather define a kudos interface completely unrelated to erc20 or tokens.

1 Like

Read through this spec, as I’m thinking about this kind of token too! I think after reading the spec and all the comments and revisions, I agree with @fulldecent 's original take on this, though. I think a restricted ERC-20 is probably the best way to go about this.

My main reasoning is it seems at this point that the only thing that is really added to the diff between this and ERC-20 (other than mint and burn, which I agree with an earlier commenter that it doesn’t make sense to put that into the spec. Reason being its very likely specific EXP implementations would need different function arguments for those functions, for things like signatures. This is why it’s not in any of the ERC-20 specs or extensions) is the concept of “Participation.”

While I think the intention is good, I don’t think it will achieve what you intend. Assuming the intention is that people won’t randomly be assigned some of these “points” without their consent, it’s easy to follow this spec while still violating this property.

For example, someone could write an implementation that emits the Participation event with true when a mint function is first called for the user, regardless of whether they actually participated. This kind of thing is ultimately always going to be up to the specific implementations of a token, and it’s going to be up to the clients displaying info to end users to counter abuse (as it already is today with token filters and such).

If someone wants to create this opt-in participation in being able to transfer ERC-20s, that’s fine. But the design surface area for the variety of ways to do that is so large, I’m not sure it makes sense to standardize that.



Beyond actual game experience point implementations, we’ve thought of a few potential ones:

  • Reddit-like Karma
  • DAO delegation of authority levels
  • Loyalty points from a business
  • Ratings for contenders in sports or other competitive leagues.
  • Credit scores (Ugh that feels dystopian, but at least it’d be more transparent and trustworthy than current credit scoring systems around the world…)
  • Kudos given for contributions of some sort, i.e. for volunteer hours at a nonprofit

@dadabit also brought up the EXP name question recently. I think experience points is a more vivid description than the others considered, but I’m open to changing it. Happy to discuss dropping “token” language altogether, but at this point I think that’s a bit extreme. The Kudos Standard? Or more verbose, The Experience Points Standard? More synonyms for “kudos”.

From the latest rationale section of the EIP:

EXP Word Choice

EXP, or experience points, are common parlance in the video game industry and generally known among modern internet users. Allocated EXP typically confers to strength and accumulates as one progresses in a game. This serves as a fair analogy to what we aim to achieve with ERC-4974 by encouraging members of a community to have more strength in that community the more they contribute.

Alternatives Considered: Soulbound Tokens, Soulbounds, Fungible Soulbound Tokens, Non-tradable Fungible Tokens, Non-transferrable Fungible Tokens, Karma Points, Reputation Tokens

Thanks for this feedback. I’m also agreed that mint and burn are not sensible here. You brought up two other major topics:

EIP-4974 versus existing token standards

Participation is definitely critical, but from my understanding there are two core, unique components of the 4974:

  1. Only the operator can transfer EXP. Other accounts have no ability to obtain or dispose of EXP.
  2. An account must set themselves as participating before any tokens can be received.

Implementing ERC-20 or ERC-721 to allow for these two components is simply not implementing ERC-20 or ERC-721. I think that’s the crux of @fulldecent 's post above, but please correct me if I’m wrong.

Potential loopholes

We can’t control if someone writes a smart contract claiming to follow a standard while quietly not following the standard, but you’re right we should be clear in the spec about what clients should expect and test for.

Thanks for pointing this out. Simply emitting a Participation event in this way shouldn’t have any impact on the operator’s ability to transfer to an address, but it would certainly be confusing. I’ll add a clause to make this explicit for each of the events, like so for Participation:

/// This event MUST ONLY be emitted by setParticipation.

I’m keen to examine more examples like this. Do you see any other logical holes for implementers to abuse the spec?

Right, but like I explained in my post, you can’t really enforce that with a specification. I think this is more appropriate as a token protocol (ie. tokens created from a base contract that can actually enforce these rules) than an EIP, in my opinion. Then, it’s easy for clients and smart contracts to trust the child tokens, because it can be easily verified that Participation is enforced at the code level!

I think you misunderstood what he is saying, actually. He’s saying that what you describe fits as a subset of the ERC-20 standard, so you can just go ahead and implement it without needing a new spec.

Neither of those two points goes against the ERC-20 spec. The ERC-20 spec does not specify how tokens can be minted or burned. And as for restricted transfers, everyone considers USDC an ERC-20, and that has a blacklist for interactions. This is no different! I’d say go with @fulldecent 's recommendation and just go for it, no need for an EIP!

Well what I’m saying is, abusers don’t tend to follow the rules :sweat_smile:. My point is, you can specify all the rules you want, the nature of smart contracts being self-sovereign and EIPs simply being agreed-on guidelines means they aren’t really too useful for preventing abuse. If someone creates a token meant to harm people, clients with filters tend to hide them pretty quick, regardless of what EIPs they follow. I’m not sure this adds enough to warrant an EIP, for that reason.

1 Like

Thanks for these comments @carlosdp, and I really appreciate the discussion you and @TimDaub had in the thread on EIP-4973.

On @fulldecent’s weekly community service hour livestream, I asked about EIPs. We didn’t discuss his comment above specifically, but I’m now convinced that your interpretation is right and mine was wrong. I was probably swept up in confirmation bias and excitement about my new idea.

I don’t want to create a standard that’s meaningless and no one will use. I’m genuinely unclear about what’s useful, though.

Where’s the line? How reductionist should we be?

At one extreme, we can argue every EIP should rather just be an optional extension to some other, more fundamental one. At the other extreme, I can envision every fly-by-night pet project getting its own ERC.

Maybe this deserves another thread. I’m confused.


Here is my overall guiding principle:

First build something. Then standardize it. And the “something” should include some producer and some consumer of information.

And a second one:

The purpose of standardizing something is to invite more people to play in your sandbox. The best way to get more people in your sandbox is to already have some friends in the sandbox.

ERC-721 is an example of something that was build–including multiple producers and consumers–before standardizing. The producer is the NFT contract, like some token that represents artwork or identity on-chain. The consumer is something that wants to query that information like Etherscan or MetaMask. Only by considering the needs of people on BOTH sides of that producer/consumer fence were we able to make the biggest impact. The end result is Etherscan fully supports ERC-721 and MetaMask finally started (barely) supporting most of it four years later and after every newspaper on earth was talking about this technical standard on its front page [citation needed] at some point. You might say MetaMask was brought along kicking and screaming.

Compare that to my recent experience in Estonia last week at NFT Tallinn. There were at least 5 companies focused on creating an NFT/fungible token for tracking carbon credits. (This is typical for an NFT event.) Few, if any, people are actually using their products. Standardizing any of that now would be a disaster. Four years from now barely anybody will have been attracted to connect onto their sandbox. And when they start connecting, they will learn some important thing they wish they know at the time of standardization. And the result will be… fragmentation with a new standard. That is the worst-case outcome for a standard.


Just as a tiny note, the standard could simply state exactly what happens if you call the disabled ERC-20 functions, and add a new ERC-165 interface for wallets to query to check if a token is an EXP.

Edit: hm, actually you’d probably want a whole new interface that defines ERC-20 compatible functions, but not advertise ERC-165 support for the ERC-20 interface.

Hi @dtedesco1,

I like the idea of a reputation token standard and have been thinking about it as well.

Here are some of my thoughts:

  • Reputation tokens are hard to earn, but easy to burn.
  • Reputation tokens cannot be transferred (period), but can be minted and staked.
  • Reputation token supply is inflationary. Total supply of reputation tokens is constant increasing so that reputation loses value over time and must be continuously earned for an owner to maintain their share of reputation tokens.

There are lots of things to work out, but a real-world example has helped me think about this. I started life as a physicist, but switched to finance ages ago. My first job in asset management had an interesting flat culture. The management team rotated every year. My office was next to the founder’s grandson and was the same modest size. No corner offices. Also, everyone in the investment team bent over backwards to help me. It was great. The way it was explained to me, everyone was enthusiastic about helping me because the sooner I got up to speed, the sooner I could help them. Sounded great. But when my first annual review came around, I learned there was a more pragmatic reason why everyone was trying so hard to help me. I received an odd email saying that I had 10 points that I could allocate to colleagues with a maximum of 5 points to any one person and could allocate to at most 10 people (1 pt each). I didn’t have to allocate any if I didn’t want to. The basis for allocation? We were to allocate points to colleagues who we felt had helped us do our jobs better the previous year. Bonuses were largely influenced by how many points you received. I always thought that was a great was to incentivize a helpful culture. Now, it seems like a total no-brainer to tokenize this concept.

With this in mind, I am thinking that once someone has achieved a certain level of reputation, e.g. maybe owning 1 reputation token, they are periodically, e.g. once a month, allowed to mint (not transfer) a limited number of tokens to others who they feel have helped them or helped the project.

The natural use case for reputation tokens would be DAO governance as means to combat the current plutocracy of purchased governance tokens. Rather than buying votes, you earn votes via reputation and you vote on initiatives by staking your reputation on them. The amount you can stake is tracked similarly to how allowance is currently tracked in ERC-20.

Need to think about Sybil attacks. Maybe some kind of modified quadratic voting?

Edit: Btw, if there is a non-transferrable token standard, I think it should also contain a consent mechanism, e.g.

  • Reputation tokens cannot be transferred (period), but can be … staked.

This is contradictory. Staking implies transferring. Or more specifically, staking means not being able to transfer something that you were previously able to transfer.

Oh, nvm, I see you are talking about being able to burn.

So this is like reputation points on StackOverflow.

As I regularly get approached by people about Soulbound tokens, and especially now at devcon, I’ve pointed people here a couple of times already. I think the idea of fungible but non-transferrable points, aka experience points, resonated with many people. I’d encourage you to pursue this @dtedesco1 further.

1 Like

Thanks for the encouragement, Tim! I will take a fresh look at this soon. Some folks are overdue responses and I’ve got to clean up the PR.

1 Like

Hey, just wanted to add that I’m using this EIP as a starting point for social tokens that can actually be redeemed for prizes. This is for an NFT project who has a “points” system for people who buy an NFT from the collection, or buy physical art from the artist behind the project. The social points are then used to redeem prizes (like 10% off) on the artist’s shop and burned. The concept of having an operator (the artist in this case) and non-transferable (between individuals), non-valued tokens is a perfect fit for what we’re wanting to experiment with.

I’ll come back to post my implementation once I have it done, but just wanted to say that I really appreciate the thought put into this EIP, which gave me a much-needed starting point for this project. I look forward to seeing where it ends up!

EDIT: Wanted to post what I’ve put together in case anyone is curious to see a non-perfect implementation :slight_smile:

1 Like