Skip to content

Commit

Permalink
Custom fees support design (#2173)
Browse files Browse the repository at this point in the history
- Add HTS custom fees design doc

Signed-off-by: Xin Li <xin.li@hedera.com>
  • Loading branch information
xin-hedera authored Jul 2, 2021
1 parent 2aafda1 commit 8730c07
Showing 1 changed file with 277 additions and 0 deletions.
277 changes: 277 additions & 0 deletions docs/design/custom-fees.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
# Custom Fees Design

## Purpose

[HIP-18](https://github.com/hashgraph/hedera-improvement-proposal/blob/master/HIP/hip-18.md) proposes changes to support
Custom Hedera Token Service Fees. This document explains how the mirror node can be updated to support it.

## Goals

- Ingest custom fees in TokenCreate and TokenFeeScheduleUpdate transactions to the database
- Ingest the fee schedule key in TokenCreate and TokenUpdate transactions to the database
- Ingest assessed custom fees in the transaction record to the database
- Expose the fee schedule key and custom fees via REST APIs
- Expose assessed custom fees via REST APIs
- Support historical token custom fees lookup

## Non Goals

## Architecture

### Database

- Add new `t_transaction_types`

```sql
insert into t_transaction_types (proto_id, name, entity_type) values (45, 'TOKENFEESCHEDULEUPDATE', 5);
```

- Update `t_transaction_results` with new response codes

- Add new columns `fee_schedule_key` and `fee_schedule_key_ed25519_hex` to table `token`

- Add a new `custom_fee` table

```sql
create table if not exists custom_fee
(
amount bigint,
amount_denominator bigint,
collector_account_id bigint,
created_timestamp bigint not null,
denominating_token_id bigint,
maximum_amount bigint,
minimum_amount bigint,
token_id bigint not null
);
create index if not exists
custom_fee__token_timestamp on custom_fee (token_id, created_timestamp desc);
```

- Add a new `assessed_custom_fee` table

```sql
create table if not exists assessed_custom_fee (
amount bigint not null,
collector_account_id bigint not null,
consensus_timestamp bigint not null,
token_id bigint
);
create index if not exists assessed_custom_fee__consensus_timestamp
on assessed_custom_fee (consensus_timestamp);
```

## Importer

### Domain

- Add `AssessedCustomFee` class with the following fields
- `amount`
- `collectorAccountId`
- `consensusTimestamp`
- `tokenId`

- Add `CustomFee` class with the following fields
- `amount`
- `amountDenominator`
- `collectorAccountId`
- `createdTimestamp`
- `hasCustomFee`
- `denominatingTokenId`
- `maximumAmount`
- `minimumAmount`
- `tokenId`

### Custom Fee Parsing

Both new domain objects are insert-only.

#### EntityListener

- Add a `onAssessedCustomFee()` to handle inserts on the `assessed_custom_fee` table
```java
default void onAssessedCustomFee(AssessedCustomFee assessedCustomFee) throws ImporterException {
}
```

- Add a `onCustomFee()` to handle inserts on the `custom_fee` table
```java
default void onCustomFee(CustomFee CustomFee) throws ImporterException {
}
```

#### EntityRecordItemListener

- Add a function `insertAssessedCustomFees()` to insert assessed custom fees in a transaction record
- Add a function `insertCustomFees()` to insert custom fees in TokenCreate / TokenFeeScheduleUpdate transaction body
- Update `insertTokenCreate` to save the fee schedule key and insert a token's custom fees
- Update `insertTokenUpdate` to save the updated fee schedule key
- Add a function `insertTokenFeeScheduleUpdate` to insert updated custom fees of a token

#### PgCopy in `SqlEntityListener`

- Add pgcopy for domain class `AssessedCustomFee`

- Add pgcopy for domain class `CustomFee`

#### Transaction Handler

- Add a new transaction handler `TokenFeeScheduleUpdateTransactionHandler` to extract the token entity and update
the modified timestamp of the entity

## REST API

### Transactions Endpoint

- Update `/api/v1/transactions/{id}` response to add assessed custom fees. Note if an assessed custom fee have a `null`
`token_id`, it's charged in HBAR; otherwise it's charged in the `token_id`

```json
{
"transactions": [
{
"consensus_timestamp": "1234567890.000000001",
"valid_start_timestamp": "1234567890.000000000",
"charged_tx_fee": 7,
"memo_base64": null,
"result": "SUCCESS",
"transaction_hash": "aGFzaA==",
"name": "TOKENTRANSFER",
"node": "0.0.3",
"transaction_id": "0.0.10-1234567890-000000000",
"valid_duration_seconds": "11",
"max_fee": "33",
"transfers": [
{
"account": "0.0.9",
"amount": 10
},
{
"account": "0.0.10",
"amount": -161
},
{
"account": "0.0.98",
"amount": 1
},
{
"account": "0.0.87501",
"amount": 150
}
],
"token_transfers": [
{
"account": "0.0.200",
"amount": 200,
"token_id": "0.0.90000"
},
{
"account": "0.0.10",
"amount": -1210,
"token_id": "0.0.90000"
},
{
"account": "0.0.400",
"amount": 1000,
"token_id": "0.0.90000"
},
{
"account": "0.0.87502",
"amount": 10,
"token_id": "0.0.90000"
}
],
"assessed_custom_fees": [
{
"amount": 150,
"collector_account_id": "0.0.87501",
"payer_account_id": "0.0.10",
"token_id": null
},
{
"amount": 10,
"collector_account_id": "0.0.87502",
"payer_account_id": "0.0.10",
"token_id": "0.0.90000"
}
]
}
]
}
```

### Token Info

Add `fee_schedule_key` and `custom_fees` to the response json object of `/api/v1/tokens/:id`

```json
{
"token_id": "0.0.1135",
"symbol": "ORIGINALRDKSE",
"admin_key": null,
"auto_renew_account": null,
"auto_renew_period": null,
"created_timestamp": "1234567890.000000002",
"decimals": "1000",
"expiry_timestamp": null,
"freeze_default": false,
"freeze_key": null,
"initial_supply": "1000000",
"kyc_key": null,
"max_supply": "9223372036854775807",
"modified_timestamp": "1234567899.000000002",
"name": "Token name",
"supply_key": null,
"supply_type": "INFINITE",
"total_supply": "1000000",
"treasury_account_id": "0.0.98",
"type": "FUNGIBLE_COMMON",
"wipe_key": null,
"fee_schedule_key": {
"_type": "ProtobufEncoded",
"key": "7b2231222c2231222c2231227d"
},
"custom_fees": {
"created_timestamp": "1234567896.000000001",
"fixed_fees": [
{
"amount": 10,
"collector_account_id": "0.0.99812",
"denominating_token_id": null,
},
{
"amount": 10,
"collector_account_id": "0.0.99813",
"denominating_token_id": "0.0.10020"
}
],
"fractional_fees": [
{
"amount": {
"numerator": 1,
"denominator": 10
},
"collector_account_id": "0.0.99820",
"maximum": 200,
"minimum": 50
},
{
"amount": {
"numerator": 3,
"denominator": 20
},
"collector_account_id": "0.0.99821",
"minimum": 10
}
]
}
}
```

Add optional filters

- `/api/v1/tokens/:id?timestamp=123456789.000000001` - return the historical custom fees of a token effective at the
specified timestamp. Note the query is designed with support of historical value of other token fields but only custom
fees will be implemented.

## Non-Functional Requirements

0 comments on commit 8730c07

Please sign in to comment.