FINAL EIP-5192 - Minimal Soulbound NFTs

Maybe I wrongly assumed that your proposal was requiring the emission of events at status change.
It looks like it is not Add EIP-5192 - Minimal Soulbound NFTs by TimDaub · Pull Request #5192 · ethereum/EIPs · GitHub
Actually, if it just is

interface IERC5192 {
  function locked(uint256 tokenId) external view returns (bool);
}

it looks good to me. I will remove mine and will support this.
It will force me to find a new naming for ERC721Lockable but it is ok :smiley:

Never mind, I realized that was an old implementation and the new one is here

Exchanges listen to events to update their databases. That means that OpenSea is not going to call the locked view, most likely it will assume that if no event has been emitted, the status has not changed. For this reason I suggest that the events MUST be emitted if someone implements the interface.

  /// @notice Emitted when the locking status is changed to locked.
  /// @dev If a token is minted and the status is locked, this event MUST be emitted.
  /// @param tokenId The identifier for a token.
  event Locked(uint256 tokenId);

Leaving the implementer the freedom of deciding if emitting an event or not risks to create confusion.

1 Like

Just for confirmation, the actual valid specification is always here (and it won’t change anymore because it has been marked “final”): ERC-5192: Minimal Soulbound NFTs

Exchanges listen to events to update their databases. That means that OpenSea is not going to call the locked view, most likely it will assume that if no event has been emitted, the status has not changed. For this reason I suggest that the events MUST be emitted if someone implements the interface.

Yes, sadly, true. Would you mind expanding on why sometimes emitting the Locked and Unlocked events aren’t in your interest? I understand that it’d increase your gas costs to emit those events. But e.g., for an indexer, I honestly see no better way than working with events and emitting them on every state change.

If a transaction causes a change in status, it may make sense to emit an event. In games, things are more dynamic. A token may be transferable or not depending on what happens in the game. For example, a token can only be transferred if the owner has enough rewards in the game’s ERC20 token or if they also own another token. Additionally, only one token can be transferred at a time if the owner has more assets in the same family. These issues are often resolved by staking tokens in a pool and giving up ownership. However, the current trend is to allow the owner to keep ownership while locking the token in different ways. In this case, the feature that is most affected is the transferability. I believe that emitting events makes sense with Soulbound NFTs, but not with NFTs used in games or other dynamic environments. That is why I suggest a minimalistic interface that only tells the caller if the token is transferable or not, ignoring the nature of the token. In my opinion, a Soulbound token is just one example of a non-transferable token and we should not create a standard for this sub-case. Of course, this is just my opinion and I may not be correct.

1 Like

That is true as long as the indexer can count on the event, i.e., if the event is mandatory.
However, if the standard does not require events and just exposes a view, an exchange is forced to call the view. If not all the tokens emit the events, of course, the exchange is anyway forced to call the view, but that would be a failure.

I’ve been working on a project called ERC721Lockable. The goal is to allow individuals to stake their NFTs in a pool without losing ownership of the NFTs. I created it for a specific use case in the game Everdragons2, where players can stake their dragons to earn rewards, but still maintain the ability to vote on the dragon as a governance token. I’ve recently updated the project to extend IERC5192. I would appreciate your input on the project, particularly on the naming. If it makes sense for you, you can also list it as an implementation of your ERC in a scenario different than Soulbound tokens.

I apologize for joining this discussion at such a late stage. However, as the issue has not yet been finalized, I would like to propose a solution to the problem of lockable tokens that cannot emit events.

If we were to have two separate interfaces:

interface IERC5192 {
  function locked(uint tokenId) external view returns(bool);
}

and

interface IERC5192Extended is IERC5192 {
  // events MUST be emitted
  event Locked(uint tokenId);
  event Unlocked(uint tokenId);
}

This would solve the problem at hand. A contract that cannot emit events would implement the first interface, while a contract that can do so would implement the second. The main benefit of this approach is that in the second interface, the emission of events can be made mandatory, which would resolve the dilemma faced by marketplaces (not being able to trust the events, if they “should” be emitted, but may not).

From the EIP’s Security Concerns section: There are no security considerations related directly to the implementation of this standard.

It might be worth mentioning some critical, relevant security concerns in the EIP. For instance:

  • The contract should have proper access controls to ensure that only authorized parties (e.g. the contract owner) can lock or unlock tokens.
  • Care should be taken to ensure that the locking function cannot be called multiple times on the same token, as this could potentially lead to the token being permanently locked by an attacker.
  • The contract should have a mechanism to handle emergency situations, such as a way to unlock the token in case the original owner loses access to their account.
  • It’s important to also consider the security of the EIP-165 and EIP-721 that this EIP is based on.

I get that these mostly aren’t “directly” related to the functionality of the extension, but the extension only works if there’s a locking function added to the NFT contract. That locking function is probably getting written at the same time as this extension is getting implemented, so it might be worth calling out the key security concerns.

1 Like

I wrote a blog post about why Lockable Tokens are needed.

The Red Whale that Killed the Ocean DAO

I came across a proposal to change the name, which can be found here:
Update EIP-5192: Change name to "Lockable tokens" by TimDaub · Pull Request #6330 · ethereum/EIPs · GitHub.
However, I believe it would be best to have a discussion on this matter, as SBT is now a well-established term and any renaming should be done with the consensus of the community to avoid potential confusion.

Please note that “lockable” alone could refer to locking of metadata. Additionally, there is already a proposal for a similar name “Lockable Non-Fungible Tokens”.

What is an SBT? I have no idea tbh.

PS: I’m disappointed that the eip5058 authors didn’t answer my call to merge our work streams in SEPTEMBER and that they’re now proposing a duplication of the work done in eip5192: EIP-5058: ERC-721 Lockable Standard - #2 by TimDaub

Certainly, as there is no direct mention of SBT in EIP, my explanation was incorrect. I apologize. The correct term is “Soulbound”. I mean the notion of soulbound is already accepted by the community.

I agree that “Minimal soulbound NFTs” is not appropriate, and the idea of SBTs should be divided into two traits: untransferability and non-fungibility, in the context of implementation. That’s why I named EIP-6268 “Untransferability Indicator for EIP-1155”. Actually, I first wanted to rename this EIP (see the first revision).

IMHO “Untransferability Indicator for EIP-721” has clearer meaning.

The goal of EIP5058 is quite different. They focus on token that can be locked, instead of being staked, with all the function that are needed to reach that goal. It is very close to the contracts I wrote for our application (GitHub - ndujaLabs/erc721lockable: A simple approach to lock NFTs without transferring the ownership), with the central difference that in my proposal is the owner of the token’s contract that whitelists the contracts authorized to lock the token, while in ERP5058, the owner of a tokenID can approve any contract, exactly like we do for spending.
I have to say that I like that approach because it is very general.
Of course, they could have extended EIP5192, as I did in my implementation after reading this thread. The only required change is to move the function isLocked to locked.

@TimDaub I made a PR to suggest the addition of a defaultLocked function in your proposal at

I made it there, because here the discussion seems not very active, while in the PR the reviewers will be required to intervene, avoiding long, not very useful discussions. Here is the text of the PR

I suggest to add

  /// @notice Returns the default locking status of an Soulbound Token
  /// @dev it avoid enforcing the emission of a Locked or Unlocked event at minting
  ///      It may be a `pure` function in most cases, but a view is more flexible
  function defaultLocked() external view returns (bool);

to the interface.

I am currently working on a security-oriented project and developing a similar interface (protector-protected-protocol/IERC721Approvable.sol at main · ndujaLabs/protector-protected-protocol · GitHub). In our case, we need to control the approvability of a token. While investigating, I realized a significant problem with emitting events (such as Locked and Unlocked) is that you have to emit them each time there’s a change. However, when you mint a token, it typically starts with a default value for every tokenId, so emitting events at that point would be a waste of gas. For instance, with a typical soulbound token that is not transferable and never will be, it does not make any sense to emit the event. This would cause that whoever is deploying such a token would not use ERC5192.

In this proposal, the emission of the event at minting is unnecessary because an external actor can check if the token supports ERC5192 and query a function that returns the default status if no events have been emitted.

late to the part, but i particularly liked this spec since it’s quite lightweight, i appreciate simplicity :slight_smile: just successfully implemented it for ERC-1155 in a way that each token id can be un/locked individually, was wondering why the spec is only applicable to 721s “officially” :thinking:

2 Likes

I focused on specifying an addon to ERC721 only because I find it difficult to understand the entirety of the ERC1155 specification. I’m familiar with ERC721 and so I decided to only specify an addon for it. But anyone is welcome to transfer the ERC-5192 logic into ERC-1155!

2 Likes

@TimDaub
Following Pandapip1 suggestion (when he closed my PR on your EIP), I made an alternative proposal.
I would have preferred to work with you on that, but it looks like when an EIP is in the final stage nothing can be changed.

I would appreciate you opinion on it.

Thanks @TimDaub for putting this together. Been working on implementing support for this standard in an ERC721 NFT.

How has market adoption been? I don’t know of anyone using ERC5192.

This is definitely something that we need. I’m working on some ideas on this, since I have worked with ERC1155 and also have the requirement. Would be basing it off the ERC5192.