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

HIP-991 update according to latest discussion #1079

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 40 additions & 179 deletions HIP/hip-991.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
hip: 991
title: Permissionless revenue-generating Topic Ids for Topic Operators
author: Michael Kantor (@kantorcodes), Ty Smith (@ty-swirldslabs)
working-group: Michael Heinrichs (@netopyr)
requested-by: TierBot
type: Standards Track
category: Core
Expand All @@ -10,7 +11,7 @@ status: Accepted
last-call-date-time: 2024-07-24T07:00:00Z
created: 2024-06-14
discussions-to: https://github.com/hashgraph/hedera-improvement-proposal/pull/991
updated: 2024-09-11
updated: 2024-11-18
---

## Abstract
Expand Down Expand Up @@ -90,28 +91,12 @@ We propose adding a fixed fee mechanism to the Hedera Consensus Service (HCS) fo
* 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.
* A `ConsensusSubmitMessageTransactionBody` will include a new optional field `max_custom_fee` that a user can set to limit the paid custom fees.
* The account submitting a message to the topic will cover network transaction fees, and if necessary, a custom fee. The topic initiates the transfer of the custom fee to the fee collector using a synthetic `CryptoTransfer`, moving funds from the message sender's account to the designated fee collector.
* If the fee of submitting a message exceeds the `max_custom_fee`, the transaction will fail with an appropriate error. The sender still pays node and network fees for failed transactions.
* 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 node and network fees for failed transactions.

#### Fee Exclusions

Expand All @@ -123,7 +108,7 @@ We propose adding a fixed fee mechanism to the Hedera Consensus Service (HCS) fo

##### 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.
If the FEKL list contains duplicate keys, the `ConsensusCreateTopicTransaction`, respectively `ConsensusUpdateTopicTransaction`, will fail with a `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

Expand All @@ -139,16 +124,15 @@ When creating a topic, the FEKL list is independent and must be explicitly popul

### HIP Parameters

After discussing with the engineering team, the HIP parameters are defined as follow:
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.
* When submitting a message to a topic with custom fees through an application or wallet interface, users must set the maximum fee for the message. Alternatively, users can add a flag to accept all custom fees from a topic id. If the topic has no custom fees, neither is required.
* 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.

Expand Down Expand Up @@ -193,7 +177,7 @@ message ConsensusCreateTopicTransactionBody {
repeated Key fee_exempt_key_list = 9;
/**
* The custom fee to be assessed during a message submission to this topic
* The custom fee to be assessed during a message submission to this topic. Empty if no custom fees are applied.
*/
repeated ConsensusCustomFee custom_fees = 10;
}
Expand All @@ -207,17 +191,17 @@ The `ConsensusUpdateTopicTransactionBody` message is updated to include the opti
message ConsensusUpdateTopicTransactionBody {
[..]
/**
* Access control for update/delete of custom fees. Null if there is no key.
* Access control for update/delete of custom fees. Null if the key should not be updated.
*/
Key fee_schedule_key = 10;
/**
* If the transaction contains a signer from this list, no custom fees are applied.
* If the transaction contains a signer from this list, no custom fees are applied. Null if the list should not be updated.
*/
FeeExemptKeyList fee_exempt_key_list = 11;
/*
* The custom fee to be assessed during a message submission to this topic
* The custom fee to be assessed during a message submission to this topic. Null if the fees should not be updated.
*/
ConsensusCustomFeeList custom_fees = 12;
Expand All @@ -232,6 +216,25 @@ message ConsensusCustomFeeList {
}
```

#### ConsensusSubmitMessageTransactionBody

The `ConsensusSubmitMessageTransactionBody` message is updated to include the optional `max_custom_fees` property for specifying the maximum fee that the user is willing to pay for the message.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to call out that there's a method to set accepts all fees in this section?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the flag accept_all_fees

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that the user must set either a max_custom_fees or set the accept_all_custom_fees to true. We can add a validation to throw an error if accept_all_custom_fees=false and max_custom_fees is not set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed. If a topic has custom fees and neither max_custom_fees nor accept_all_custom_fees are set, the message will fail anyway because the fees cannot be paid.


```protobuf
message ConsensusSubmitMessageTransactionBody {
[..]
/**
* The maximum custom fee that the user is willing to pay for the message. This field will be ignored if `accept_all_custom_fees` is set to `true`.
*/
repeated FixedFee max_custom_fees = 4;
/**
* If set to true, the transaction will accept all custom fees from the topic id
*/
bool accept_all_custom_fees = 5;
}
```

#### ConsensusTopicInfo

The `ConsensusTopicInfo` message is updated to include the Fee Schedule Key and the current list of custom fixed fees associated with the topic.
Expand All @@ -256,91 +259,6 @@ message ConsensusTopicInfo {
}
```

#### ConsensusApproveAllowanceTransactionBody

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

```protobuf
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.

```protobuf
/**
* 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.

```protobuf
/**
* 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:
Expand All @@ -350,61 +268,6 @@ To comply with this HIP, the Mirror Node provides the following features:

#### 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.

```json
{
"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.

```json
{
"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.

Expand Down Expand Up @@ -455,10 +318,6 @@ Here is the list of endpoints affected by this HIP and the expected changes.
}
```

* `/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.
Expand All @@ -472,9 +331,7 @@ There are no known backward compatibility issues. Existing topics without custom

## 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.
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, the user can set a maximum charge for each message.

## How to Teach This

Expand All @@ -496,7 +353,7 @@ 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
.setAmount(100) // 100 tokens are transferred to the fee collecting account each time a message is submitted to the topic
.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

Expand All @@ -519,9 +376,14 @@ transactionResponse = new TopicAllowanceApproveTransaction()

[...]

// Define max custom fee
const maxCustomFee = new FixedFee()
.setAmount(100) // a maximum of 100 tokens is paid for submitting the message
.setDenominatingTokenId(TokenId.fromString("0.0.56789")); // The token to charge the fee in. HBAR if unset

// 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.
.setMaxCustomFees([maxCustomFee]) // Set the maximum fee for the message
.execute(client);

```
Expand All @@ -531,7 +393,6 @@ This implementation shows the creation of a topic where each message submission
## 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

Expand Down
Loading