GitHub Logo HIP-991: Permissionless revenue-generating Topic Ids for Topic Operators

Author Michael Kantor, Ty Smith
Requested By TierBot
Discussions-To https://github.com/hashgraph/hedera-improvement-proposal/pull/991
Status Accepted
Needs Council Approval Yes
Review period ends Wed, 24 Jul 2024 07:00:00 +0000
Type Standards Track
Category Core
Created 2024-06-14
Updated 2024-09-11

Abstract

This document outlines the development of a fixed fee system for the submission of topic messages on the Hedera network. It addresses the need for improved economic scalability and aims to enhance resource allocation and revenue distribution mechanisms for topic operators. It also seeks to simplify engineering complexity for dApp developers on the Hedera network.

Background and Motivation

Problems to Solve:

  • Dynamic Restriction of Access to Topic Writing: Users currently face difficulties when creating new topic IDs because they must choose between making the topic publicly writable for a very low cost or implementing a complex web architecture to manage access through the submit key. This complexity can hinder user experience and development efficiency.
  • Ease of Monetization: Developers and businesses find it challenging to charge users for submitting information to a topic due to the lack of a native fee structure. A built-in payment system would streamline monetization, allowing developers to easily charge for topic submissions, which can enhance the financial viability of their applications.
  • Resource Allocation: The current low fee of $0.0001 per message makes it difficult for topic operators to manage and predict the economic impact of high-traffic topics. Users can suffer from spam and unexpected messages that operators have to handle, potentially degrading the quality of service.
  • Token and HBAR Utilization: There is an opportunity to expand the utility of various tokens within the Hedera ecosystem. By allowing fees to be paid in tokens other than HBAR, such as those required by DAOs, users can leverage their token holdings for topic submissions, enhancing the ecosystem’s flexibility and user engagement.

Feature Summary:

  • HCS topics can have an optional fee for submitting messages. Fees can be set in HBAR or HTS fungible tokens.
  • HCS topics have now a new Fee Schedule Key. This key can manage fee updates. The key can be set at creation time and updated later (similarly to HTS tokens). If the HCS topic was created without a Fee Schedule Key, it cannot be added later.
  • Topic fees can be distributed similarly to fixed fees on the HTS, supporting multiple wallets and Fungible tokens in addition to HBAR.
  • HCS topics can have a list of keys that are allowed to send free messages.
  • Security measures to prevent unauthorized access to fee configurations and distributions.
  • Security measures to prevent users from being induced to pay unforeseen charges.
  • Distribution of collected fees akin to fixed fees on tokens, with support for distribution to multiple account IDs.

Benefits:

  • Provides predictable revenue per message for topic operators.
  • Enables new products and business models on HCS.
  • Increases node revenue for network fees tied to new HCS transactions/topic creations with fixed fees.
  • Enhances the utility of HCS within Hedera.
  • Increases revenue streams for node operators.
  • Enables simple facilitation of holding and spending tokens to document new information on a topic.

Related Requests:

This enhancement is in response to community feedback (Tier Bot) requesting more versatile and predictable economic models within topic IDs on the Hedera network.

User personas and stories

User Personas:

  • Topic Operator: Entities or individuals who manage and operate topics, interested in stable revenue and easy management of topic-related transactions.
  • Topic Operator: Entities or individuals who manage and operate topics, interested in reducing the noise of public topic IDs/making it more difficult to spam an open topic.
  • Regular User: End users who interact with topics, adding paid methods of interaction and submission to topics.

User Stories:

  • As a Topic Operator, I want to set a fixed fee for submitting messages to my topic, so that I can ensure a consistent revenue stream and manage my topic effectively.
  • As a Regular User, I want to know the exact cost of interacting with a topic.

Specification

Overview

We propose adding a fixed fee mechanism to the Hedera Consensus Service (HCS) for topic messages, similar to the custom fee structures in the Hedera Token Service (HTS). This will involve creating new protocol buffers (protobuf) messages and modifying existing ones to accommodate fixed fees for topics.

Requirements and Scope

Main

  • Topics may have fees for submitting messages.

Fees Definition

  • Fees are defined as a list of custom fee.
  • The list of custom fees can contain a maximum of MAX_CUSTOM_FEE_ENTRIES_FOR_TOPICS entries.
  • A custom fee is defined leveraging the HTS’s FixedFee data structure (see ConsensusCustomFee).
  • A custom fee can be set in HBAR or HTS fungible tokens and must have an accountID as the receiver.

Fee Management

  • Fees can be set at creation time.
  • Fees can be changed (updated or removed) in a topic with an update topic transaction signed by the Fee Schedule Key.
  • Topics can have a Fee Schedule Key set at creation time.
  • The Fee Schedule Key can manage fee updates for the topic.
  • The Fee Schedule Key can be updated according to the same rules that currently apply to the Submit key. In addition, to update the Fee Schedule Key, the new key must sign the transaction.
  • If the topic was created without a Fee Schedule Key, the key cannot be added later.

Fee Payment Pre-Requisites

  • The fee payer must set an allowance (total fees and maximum fee per message) in HBAR or HTS tokens to be used to pay fees for message submissions on an HCS topic basis.
  • Allowance granted to a Topic ID does not allow the Topic’s Admin Key (or any of the Topic’s keys) to spend that allowance outside of fee payments.

Fee Payment Pre-Requisites (SDK)

  • When using the official SDK, the allowance transaction uses the MAX_FEES value for total fees and maximum fees per message by default. Developers must explicitly set these values if they don’t want the defaults to be applied.
  • When sending HCS messages via the SDKs, applications must set the allowCustomFeesPayment flag to true.
  • The default value of the allowCustomFeesPayment flag is false.
  • If the allowCustomFeesPayment flag is not set or is not true, the SDK returns an error.
  • The allowCustomFeesPayment flag exists only in the SDK and isn’t enforced by the network.

Allowance Transactions

  • An account submits a transaction to grant an allowance (total fees and maximum fee per message) to a topic for both HBAR and HTS tokens. This transaction type reuses the existing allowance concept, with no need for a separate delete allowance transaction. To remove an allowance, the user will submit the same transaction with the allowance values set to 0 or a dedicated flag indicating allowance removal.
  • This allowance only permits the topic to pay for the custom fees when messages are submitted, not for any other purpose.

Fee Payment

  • The account submitting a message to the topic will cover network transaction fees, and if necessary, a custom fee via the approved allowance. The topic initiates the transfer of the custom fee to the fee collector using transferFrom, moving funds from the message sender’s account to the designated fee collector.
  • No balance will be held by the topic itself. Funds remain in the sender’s account, and insufficient funds will result in the message submission failing with an appropriate error. The sender still pays network fees for failed transactions.

Fee Exclusions

  • Topics can have a Fee Exempt Key List (FEKL)
  • FEKL can be set at creation time
  • FEKL can be updated with a ConsensusUpdateTopicTransaction signed by the topic’s Admin Key
  • FEKL has a maximum of MAX_ENTRIES_FOR_FEE_EXEMPT_KEY_LIST entries.
  • If a TopicMessageSubmitTransaction is submitted to the network and it contains a signature from a key included in the FEKL, no fees will be charged for that message.
Handling Duplicates

If the FEKL list contains duplicate keys, the transaction will fail with an FEKL_CONTAINS_DUPLICATED_KEYS error. This ensures that duplicate entries are not silently ignored, preventing potential bugs or issues in the calling code.

Signatures for Invalid/Inactive/Deleted Accounts

The FEKL list will only require keys to be formally valid as per protobuf specifications, meaning they must be correctly formatted key structures. These are keys, not accounts. Even if an account associated with a key is inactive, deleted, or non-existent, the key itself can still be added to the FEKL.

Threshold Keys

Threshold keys are supported in the FEKL. To avoid paying custom fees, the threshold must be met, meaning that the number of required signatures from the FEKL must be satisfied for a message submission. Any valid threshold key configuration will be processed normally.

Pre-Filled Keys in FEKL

When creating a topic, the FEKL list is independent and must be explicitly populated. By default, the FEKL will not include the Admin Key, Submit Key, or Fee Schedule Key, unless explicitly provided in the creation or update transaction. The SDK might suggest default behavior, but the HIP doesn’t enforce automatic inclusion of these keys in the FEKL.

HIP Parameters

After discussing with the engineering team, the HIP parameters are defined as follow:

  • MAX_CUSTOM_FEE_ENTRIES_FOR_TOPICS = 10
  • MAX_ENTRIES_FOR_FEE_EXEMPT_KEY_LIST = 10
  • MAX_FEE = unsigned int 64

User Flows and Interaction

  • Users will specify the fee settings during the topic creation process through a simple interface in their Hedera client (refer to the creation of token custom fees/fixed fee for reference).
  • Before submitting a message to a topic through an application or wallet interface, users must set an allowance and a maximum fee per message.
  • In case of user wallets, applications show the custom fees to the user before submitting the message.
  • Operators will get fee collections and distributions automatically through the custom fees just like they do in the token service currently.

New and Modified Protobuf Messages

The following is a list of modifications to the protobuf messages structure to comply with the above requirements.

ConsensusCustomFee

The ConsensusCustomFee message defines the type of fee and the account ID receiving the fee assessed during a message submission to the associated topic. A custom fee may only be a FixedFee and must specify a fee collector account to receive the assessed fees. FixedFee is an existing protobuf message and it must not be modified.

message ConsensusCustomFee {
  /**
  * Fixed fee to be charged
  */
  FixedFee fixed_fee = 1;

  /**
  * The account to receive the custom fee
  */
  AccountID fee_collector_account_id = 2;
}

ConsensusCreateTopicTransactionBody

The ConsensusCreateTopicTransactionBody message is updated to include the optional Fee Schedule Key, the optional Fee Exempt Key List, and the custom_fees property for specifying fixed fees during topic creation.

message ConsensusCreateTopicTransactionBody {
  [...]

  /**
    * Access control for update/delete of custom fees. Null if there is no key.
    */
  Key fee_schedule_key = 8;

  /**
    * If the transaction contains a signer from this list, no custom fees are applied.
    */
  repeated Key fee_exempt_key_list = 9;

  /**
    * The custom fee to be assessed during a message submission to this topic
    */
  repeated ConsensusCustomFee custom_fees = 10;
}

ConsensusUpdateTopicTransactionBody

The ConsensusUpdateTopicTransactionBody message is updated to include the optional Fee Schedule Key, the optional Fee Exempt Key List, and the custom_fees property for specifying fixed fees during topic creation.

message ConsensusUpdateTopicTransactionBody {
  [..]
  /**
    * Access control for update/delete of custom fees. Null if there is no key.
    */
  Key fee_schedule_key = 10;

  /**
    * If the transaction contains a signer from this list, no custom fees are applied.
    */
  FeeExemptKeyList fee_exempt_key_list = 11;

  /*
   * The custom fee to be assessed during a message submission to this topic
   */
  ConsensusCustomFeeList custom_fees = 12;

}

message FeeExemptKeyList {
  repeated Key keys = 1;
}

message ConsensusCustomFeeList {
  repeated ConsensusCustomFee fees = 1;
}

ConsensusTopicInfo

The ConsensusTopicInfo message is updated to include the Fee Schedule Key and the current list of custom fixed fees associated with the topic.

message ConsensusTopicInfo {
  [...]
  /**
    * Access control for update/delete of custom fees. Null if there is no key.
    */
  Key fee_schedule_key = 10;

  /**
    * If the transaction contains a signer from this list, no custom fees are applied.
    */
  repeated Key fee_exempt_key_list = 11;

  /*
   * The custom fee to be assessed during a message submission to this topic
   */
  repeated ConsensusCustomFee custom_fees = 12;
}

ConsensusApproveAllowanceTransactionBody

The ConsensusApproveAllowanceTransactionBody message is added and includes one or more ConsensusCryptoFeeScheduleAllowance and one or more ConsensusTokenFeeScheduleAllowance messages.

message ConsensusApproveAllowanceTransactionBody {
  /**
   * List of hbar allowances approved by the account owner.
   */
  repeated ConsensusCryptoFeeScheduleAllowance consensus_crypto_fee_schedule_allowances = 4;

  /**
   * List of fungible token allowances approved by the account owner.
   */
  repeated ConsensusTokenFeeScheduleAllowance consensus_token_fee_schedule_allowances = 5;
}

ConsensusCryptoFeeScheduleAllowance

This is a new protobuf message definition to enable crypto allowance for topics.

/**
 * An approved allowance of hbar transfers for a spender.
 */
message ConsensusCryptoFeeScheduleAllowance {
  /**
   * The account ID of the hbar owner (ie. the grantor of the allowance).
   */
  AccountID owner = 1;

  /**
   * The topic ID enabled to spend fees from the hbar allowance.
   */
  TopicID spender = 2;

  /**
   * The amount of the spender's allowance in tinybars.
   */
  uint64 amount = 3;

  /**
   * The maximum amount of the spender's token allowance per message.
   */
  uint64 amount_per_message = 4;
}

ConsensusTokenFeeScheduleAllowance

This is a new protobuf message definition to enable token allowance for topics.

/**
 * An approved allowance of fungible token transfers for a spender.
 */
message ConsensusTokenFeeScheduleAllowance {
  /**
   * The token that the allowance pertains to.
   */
  TokenID tokenId = 1;

  /**
   * The account ID of the token owner (ie. the grantor of the allowance).
   */
  AccountID owner = 2;

  /**
   * The topic ID enabled to spend fees from the token allowance.
   */
  TopicID spender = 3;

  /**
   * The maximum amount of the spender's token allowance.
   */
  uint64 amount = 4;

  /**
   * The maximum amount of the spender's token allowance per message.
   */
  uint64 amount_per_message = 5;
}

Mirror Node

To comply with this HIP, the Mirror Node provides the following features:

  • Support for querying a topic’s allowances and custom fees via REST APIs. This may include listing all accounts that have granted allowances to a particular topic.
  • Custom fees should be able to be queried by topic, in the same structure as custom fees exist and can be queried on token entities.

REST API changes

Here is the list of endpoints affected by this HIP and the expected changes.

  • /api/v1/accounts/{idOrAliasOrEvmAddress}/allowances/crypto
    • The endpoint lists allowances set by both CONSENSUSAPPROVEALLOWANCE and CRYPTOAPPROVEALLOWANCE
    • Changes to query parameters. Topic IDs are valid parameters for the spender.id field.
    • Changes in the body of the response. The response includes the new amount_per_message field, and may include topic IDs in the spender field. A sample response payload follows.
    {
      "allowances": [
        {
          "amount": 75,
          "amount_per_message": 5,
          "amount_granted": 100,
          "owner": "0.0.2",
          "spender": "0.0.2",
          "timestamp": {
            "from": "1586567700.453054000",
            "to": "1586567700.453054000"
          }
        }
      ],
      "links": {
        "next": null
      }
    }
    
  • /api/v1/accounts/{idOrAliasOrEvmAddress}/allowances/tokens
    • The endpoint lists allowances set by both CONSENSUSAPPROVEALLOWANCE and CRYPTOAPPROVEALLOWANCE
    • Changes to query parameters. Topic IDs are valid parameters for the spender.id field.
    • Changes in the body of the response. The response includes the new amount_per_message field, and may include topic IDs in the spender field. A sample response payload follows.
    {
      "allowances": [
        {
          "amount": 75,
          "amount_per_message": 5,
          "amount_granted": 100,
          "owner": "0.0.2",
          "spender": "0.0.2",
          "timestamp": {
            "from": "1586567700.453054000",
            "to": "1586567700.453054000"
          },
          "token_id": "0.0.2"
        }
      ],
      "links": {
        "next": null
      }
    }
    
  • /api/v1/topics/{topicId}
    • Changes to the body of the response. The response should include three new fields: fee_schedule_key, fee_exempt_key_list, and custom_fee. The fields will expose any data defined in their corresponding protobuffer definition. A sample response payload follows.
    {
      "admin_key": {
        "_type": "ProtobufEncoded",
        "key": "421050820e1485acdd59726088e0e4a2130ebbbb70009f640ad95c78dd5a7b38"
      },
      "auto_renew_account": "0.0.2",
      "auto_renew_period": 7776000,
      "created_timestamp": "1586567700.453054000",
      "custom_fees": {
        "created_timestamp": "1234567890.000000001",
        "fixed_fees": [
          {
            "amount": 100,
            "collector_account_id": "0.1.5",
            "denominating_token_id": "0.10.8"
          }
        ]
      },
      "deleted": false,
      "fee_exempt_key_list": [
        {
          "_type": "ProtobufEncoded",
          "key": "421050820e1485acdd59726088e0e4a2130ebbbb70009f640ad95c78dd5a7b38"
        },
        {
          "_type": "ProtobufEncoded",
          "key": "421050820e1485acdd59726088e0e4a2130ebbbb70009f640ad95c78dd5a7b39"
        }
      ],
      "fee_schedule_key": {
        "_type": "ProtobufEncoded",
        "key": "421050820e1485acdd59726088e0e4a2130ebbbb70009f640ad95c78dd5a7b38"
      },
      "memo": "topic memo",
      "submit_key": {
        "_type": "ProtobufEncoded",
        "key": "421050820e1485acdd59726088e0e4a2130ebbbb70009f640ad95c78dd5a7b38"
      },
      "timestamp": {
        "from": "1586567700.453054000",
        "to": "1586567700.453054000"
      },
      "topic_id": "0.0.2"
    }
    
  • /api/v1/transactions
    • Changes in query parameters. The new allowance transaction type CONSENSUSAPPROVEALLOWANCE is included in the list of supported transaction type for the transactiontype parameter.
    • Changes in the body of the response. The endpoint returns the same fields as CRYPTOAPPROVEALLOWANCE.

SDKs

This document does not include the details of the implementation updates required by the SDKs to comply with the HIP-991 specifications. However, a suggested example for the JavaScript SDK is described in the SDK Reference Implementation section.

Backwards Compatibility

The HIP introduces new features while ensuring compatibility and integration with existing Hedera network protocols and services. New topics with custom fees will require appropriate updates to the Hedera SDKs, mirror nodes, and applications to support the new fee structures. There are no known backward compatibility issues. Existing topics without custom fees will continue to function as they currently do.

Security Implications

The introduction of custom fees adds another layer of economic control, but also introduces potential vectors for abuse, such as fee manipulation. To address these issues, this HIP adheres to current security requirements regarding the authorization of moving user funds. In particular, before being able to send paid HCS messages to a topic, users should first set an allowance for the recipient topic, just as in the case of HTS, to allow payment of fixed or custom fees. The user can also set a maximum charge per message.

At the network level, the default value for both allowance parameters is 0. At SDK level, the fees (total maximum amount and maximum fee per message) are always the maximum amount MAX_FEE. For this reason, the SDK documentation should contain a considerable callout on this point and be clear about the implications of not changing these default values.

How to Teach This

TBD

SDK Reference Implementation

The following is a pseudo code example for creating a topic with a fixed fee, setting the fee, and sending a message.

// Create the Hedera client
const client = Client.forTestnet();

// Define the submit key
const submitKey = PrivateKey.generate();

// Define the fee collector account ID
const feeCollectorAccountId = AccountId.fromString("0.0.12345");

// Define the fixed fee
const topicCustomFee = new TopicCustomFee()
  .setAmount(100) // 100 tokens are transferred to the fee collecting account each time this token is transferred
  .setDenominatingTokenId(TokenId.fromString("0.0.56789")) // // The token to charge the fee in. HBAR if unset
  .setFeeCollectorAccountId(feeCollectorAccountId); // 100 tokens are sent to this account for each HCS message to the topic

// Create the topic with the custom fee
const transactionResponse = await new TopicCreateTransaction()
  .setTopicMemo("Example Topic with Fixed Fee")
  .setTopicCustomFees([topicCustomFee]) // List of custom fees. In this example, a single fixed fee in tokens
  .execute(client);

// Request the receipt of the transaction
const receipt = await transactionResponse.getReceipt(client);
console.log(`Created topic with ID: ${receipt.topicId}`);

[...]

// Set allowance
const spenderTopicId = new TopicID("0.0.54321")
transactionResponse = new TopicAllowanceApproveTransaction()
    .approveHbarAllowance(ownerAccount, spenderTopicId, Hbar.from(100), Hbar.from(2)); // Set owner, topicId, maximum allowance, and max per message
    
[...]

// Send message to the topic
transactionResponse = await new TopicMessageSubmitTransaction({ topicId: topicId, message: "Hello, HCS!" })
  .setAllowCustomFeesPayment(true) // Make the agreement on payment explicit at the application level. Useful for any backend / non-front-user-facing application.
  .execute(client);

This implementation shows the creation of a topic where each message submission requires a fixed fee of 100 tokens with ID 0.0.56789, collected by the specified account.

Rejected Ideas

  • Setting a mandatory network enforced allowCustomFeesPayment flag in HCS message transactions to allow payment of fees.
  • Setting 0 as default in SDKs for maximum fees.

References

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: