GitHub Logo HIP-540: Change Or Remove Existing Keys From A Token

Author Cooper Kunz, Justyn Spooner
Working Group Jason Fabritz, Michiel Mulders, Ashe Oro
Requested By Hedera
Discussions-To https://github.com/hashgraph/hedera-improvement-proposal/discussions/522
Status Accepted
Needs Council Approval Yes
Review period ends Mon, 03 Jul 2023 07:00:00 +0000
Type Standards Track
Category Service
Created 2022-08-05
Updated 2024-03-22

Abstract

All entities across Hedera have opt-in administrative keys. Currently, the Consensus Service and File service allow these keys to be removed (making the entities immutable). However the Hedera Token Service does not provide such a feature consistently. We should enable existing administrative keys for tokens created with the Hedera Token Service to be able to sign an update transaction that changes or permanently removes any privileged key (Admin, Wipe, KYC, Freeze, Pause, Supply, Fee Schedule, Metadata) from the entity.

Motivation

Many NFT projects require that their token remains immutable yet some project owners have unknowingly created NFTs with keys such as Admin, Wipe, Freeze and Pause keys set, which undermines this assumption.

The majority of collectors will also be unaware of the implications of having these keys set on the NFTs they have purchased.

For example, an NFT with a Wipe Key set poses a risk to the owner that the NFT could at any point be burned even though it’s not in the treasury account.

Right now there is no way to remove keys (Admin, Wipe, KYC, Freeze, Pause, Supply, Fee Schedule, Metadata) from a Token. They can only be changed when the TokenUpdateTransaction is signed by the admin key.

Rationale

Currently you’re either in an admin world, or an admin-less world, on Hedera. It’s often preferable to launch in an administrative capacity to ensure things are operating smoothly, and transition into a more admin-less world overtime.

We should also let creators fix mistakes in their token keys. We present some community comments around the subject below:

Ashe Oro raised the following question in this tweet

What % of #Hedera NFTs have either an Admin, Wipe or Freeze key set?

@TMCC_Patches responded with these stats:

With wipe or freeze keys: 66,914

Without: 707,178

A large proportion of the creators of those 66,914 NFTs are likely unaware of the implications those keys have on their collection.

There are a number of high profile NFT collections circulating right now that have some or all of these keys set. After reaching out to a few of the creators, the first thing they have all said is that they did not realise and how can we remove them.

These conversations have led to this HIP as right now there is no way for a creator to address this issue in their collections which are already distributed to collectors.

DPub raises a requirement for this on Discord here

…can you remove the admin key? Use case - is setup the token, mint - make sure it is all good - if not - burn. if good - make immutable - remove adminkey and supplykey I thought we were able to - but testing - doesn’t look like there is a way to set to null. setAdminKey() doesn’t do anything. We could create a throwaway adminkey, but people might not believe that.

Topachi from Hbar Suite also raises a requirement for this feature in Discord

Could you guys please do this? Because in the future we might need to remove some keys if the community wishes, and it would be much easier with a permanent token update instead of creating a v2 of our token.

The only way to address this currently is to either:

  1. Mint a brand new collection without the admin/wipe/freeze keys set and airdrop to everyone who had the v1 version.
  2. Generate a bad key to replace the existing keys in the token as suggested in the Hedera Discord token-service channel

    There is, however, a quick-and-dirty way to make an NFT collection un-wipeable:

    • Choose a low-entropy Ed25519 public key; for example, 32 bytes of binary zeros or hex abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd.
    • In a single TokenUpdate, replace both the admin and wipe keys of the NFT collection with this public key.
    • Now to wipe an NFT in this collection, you would have to invert the SHA-512 hash function, which is…going to take a while.

Neither of these approaches is ideal and could easily be solved by allowing the keys to be wiped as part of a TokenUpdateTransaction call.

Language

First, let’s address important language to set a clear distinction between “removed” and “invalid”.

  • “Lower privilege key” refers to all keys you can set for a token except for the admin key, which is a high privilege key. In other words, the KYC, freeze, pause, wipe, supply, fee schedule, and metadata keys are considered low privilege keys.
  • “Removed” refers to not setting a key or setting it to “no key”. If a key is absent, the token is considered immutable for that key. For example, if the freeze-key is absent when the token is created, then even the admin cannot create a freeze-key later on.
  • “Invalid” refers to an invalid key, such as an all-zero key (the key is present, but no private key corresponds to it like 0x0000000000000000000000000000000000000000). There’s nothing magical about the all-zero key except we believe that it is difficult to find a private key that maps to an all-zero public key. So we recommend using all-zeros for all invalid keys.

User stories

  • As a creator I want to remove the Wipe Key using the Admin Key on my existing NFT collection so that collectors can be assured their NFT can’t be removed from their account.
  • As a creator I want to remove the Admin Key on my existing NFT collection so that I can be sure my NFT is immutable.
  • As a creator I want the flexibility to remove keys as my project evolves. For example, I might start out with KYC as a requirement and later decide that it is not necessary.
  • As an NFT minting service I want to be able to mint an NFT collection on behalf of a creator using our private key and then update the treasury account to the creator’s account whilst simultaneously removing the Admin Key so the creator ends up with an immutable NFT collection in their treasury account.
  • As an NFT creator, I want to reduce the risk profile of my NFT Collection by using a lower privilege key to update itself to an invalid key (i.e. all-zeros key) without having to use the Admin Key.

Specification

  1. Only the admin key should be able to remove itself or other keys.
  2. All keys can change themselves to another valid or invalid key (such as all-zeros).

Other Considerations

  1. We should standardize the use of all-zeros key as an invalid key across all keys in Hedera.
  2. We will have to add an enum field in the update transaction about whether the system should check the validity of the updated keys. Currently, we test the validity for all updates. With this enum field, the user will be able to tell the system to avoid checking of the validity of the updated keys. The default value of the field will maintain the current behavior of checking the validity.

Here’s a simple code example illustrating this boolean when updating a key to an invalid key.

const newSupplyKey = "0x0000000000000000000000000000000000000000";
let tokenUpdateTx = await new TokenUpdateTransaction()
    .setTokenId(tokenId)
    .setSupplyKey(newSupplyKey)
    // Interface (setKeyVerificationMode: enum = FULL_VALIDATION)
    // When set to NO_VALIDATION, the TokenUpdateTransaction won't check for the validity of the key
    .setKeyVerificationMode(NO_VALIDATION)
    .freezeWith(client)
    .sign(oldSupplyKey)

HAPI Changes

message TokenUpdateTransactionBody {
    ...
    /**
     * Determines whether the system should check the validity of the passed keys for update.
     */
    TokenKeyValidation key_verification_mode = 18;
}

/**
 * Types of validation strategies for token keys.
 */
enum TokenKeyValidation {
    /**
     * Currently the default behaviour. It will perform all token key validations.
     */
    FULL_VALIDATION = 0;

    /**
     * Perform no validations at all for all passed token keys.
     */
    NO_VALIDATION = 1;
}

Flow Diagram

There are a couple of flows to determine the immutability of a key:

  1. If a key is not set.
  2. If a lower-privilege key is set to all-zeros and no Admin Key is present.
  3. If a lower-privilege and Admin Key are set to all-zeros.

Flow Diagram Testing Immutability

Backwards Compatibility

This change is fully backward compatible & opt-in. Existing entities created with administrative keys can continue operating as desired. Entities that have been created without administrative keys can continue operating as desired.

In short, entities gain better administrative controls to manage their token.

Security Implications

Generally with administrative keys there are security requirements about how to secure and manage these secrets. This becomes increasingly important with this change, as a potential attacker could gain access to the admin keys and subsequently remove them from the entity - however, this would effectively lock/freeze them out, as it would the original administrator. These security considerations are not unique to this proposal and generally consistent with all keys attached to entities within the Hedera network.

How to Teach This

The documentation for the Token Service - Token Update would be updated to add examples on how to remove keys from a token.

Rejected Ideas

There was a discussion to introduce a dedicated method for removing keys. It opened up too many edge cases, and since the solution proposed above solves the problem, it was decided to go with that approach.

Another rejected approach is the ability to allow higher-privilege keys to change or remove themselves. However, this again opens up too many flows when, for instance, the admin key removes itself, and all lower-privilege keys become higher-privilege keys. Technically this is a sound proposal. However, it could be a better solution from a usability perspective.

References

Token Service Docs - Token Update

Copyright/license

This document is licensed under the Apache License, Version 2.0 – see LICENSE or (https://www.apache.org/licenses/LICENSE-2.0)

Citation

Please cite this document as: