Skip to content

Commit

Permalink
HIP-18 enhancement (#2419)
Browse files Browse the repository at this point in the history
- support effective payer accounts in assessed custom fee
- support netOfTransfers in fractional fee
- support royalty fee
- update openapi spec

Signed-off-by: Xin Li <[email protected]>
  • Loading branch information
xin-hedera authored Aug 18, 2021
1 parent 922abc5 commit 014b1b6
Show file tree
Hide file tree
Showing 36 changed files with 1,443 additions and 215 deletions.
110 changes: 102 additions & 8 deletions docs/design/custom-fees.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ create table if not exists custom_fee
denominating_token_id bigint,
maximum_amount bigint,
minimum_amount bigint not null default 0,
net_of_transfers boolean,
royalty_denominator bigint,
royalty_numerator bigint,
token_id bigint not null
);
create index if not exists
Expand All @@ -52,10 +55,11 @@ create index if not exists

```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
amount bigint not null,
collector_account_id bigint not null,
consensus_timestamp bigint not null,
effective_payer_account_ids bigint[] not null,
token_id bigint
);
create index if not exists assessed_custom_fee__consensus_timestamp
on assessed_custom_fee (consensus_timestamp);
Expand Down Expand Up @@ -122,8 +126,10 @@ Both new domain objects are insert-only.

### 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`
- 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`
- prior to Hedera Service 0.17.1, there is no `effective_payer_account_id`, so the `effective_payer_account_ids` will
be an empty array for those transactions with assessed custom fees

```json
{
Expand Down Expand Up @@ -184,11 +190,17 @@ Both new domain objects are insert-only.
{
"amount": 150,
"collector_account_id": "0.0.87501",
"effective_payer_account_ids": [
"0.0.87501"
],
"token_id": null
},
{
"amount": 10,
"collector_account_id": "0.0.87502",
"effective_payer_account_ids": [
"0.0.10"
],
"token_id": "0.0.90000"
}
]
Expand All @@ -201,6 +213,8 @@ Both new domain objects are insert-only.

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

For fungible tokens, the `custom_fees` object includes `fixed_fees` and `fractional_fees`.

```json
{
"token_id": "0.0.1135",
Expand Down Expand Up @@ -251,7 +265,8 @@ Add `fee_schedule_key` and `custom_fees` to the response json object of `/api/v1
"collector_account_id": "0.0.99820",
"denominating_token_id": "0.0.1135",
"maximum": 200,
"minimum": 0
"minimum": 0,
"net_of_transfers": false
},
{
"amount": {
Expand All @@ -260,7 +275,86 @@ Add `fee_schedule_key` and `custom_fees` to the response json object of `/api/v1
},
"collector_account_id": "0.0.99821",
"denominating_token_id": "0.0.1135",
"minimum": 10
"minimum": 10,
"net_of_transfers": true
}
]
}
}
```

For non-fungible tokens, the `custom_fees` object includes `fixed_fees` and `royalty_fees`.

```json
{
"token_id": "0.0.1135",
"symbol": "ORIGINALRDKSE",
"admin_key": null,
"auto_renew_account": null,
"auto_renew_period": null,
"created_timestamp": "1234567890.000000002",
"decimals": "0",
"expiry_timestamp": null,
"freeze_default": false,
"freeze_key": null,
"initial_supply": "0",
"kyc_key": null,
"max_supply": "9223372036854775807",
"modified_timestamp": "1234567899.000000002",
"name": "Token name",
"supply_key": null,
"supply_type": "FINITE",
"total_supply": "1000000",
"treasury_account_id": "0.0.98",
"type": "NON_FUNGIBLE_UNIQUE",
"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"
}
],
"royalty_fees": [
{
"amount": {
"numerator": 1,
"denominator": 10
},
"collector_account_id": "0.0.99820"
},
{
"amount": {
"numerator": 3,
"denominator": 20
},
"collector_account_id": "0.0.99821",
"fallback_fee": {
"amount": 10,
"denominating_token_id": "0.0.10020"
},
},
{
"amount": {
"numerator": 1,
"denominator": 20
},
"collector_account_id": "0.0.99821",
"fallback_fee": {
"amount": 9000,
"denominating_token_id": null
}
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@
*/

import javax.inject.Named;
import javax.persistence.Converter;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;

import com.hedera.mirror.importer.domain.EntityTypeEnum;

@Named
@javax.persistence.Converter
@Converter
@ConfigurationPropertiesBinding
public class AccountIdConverter extends AbstractEntityIdConverter {

public static final AccountIdConverter INSTANCE = new AccountIdConverter();

public AccountIdConverter() {
super(EntityTypeEnum.ACCOUNT);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.hedera.mirror.importer.converter;

/*-
* ‌
* Hedera Mirror Node
* ​
* Copyright (C) 2019 - 2021 Hedera Hashgraph, LLC
* ​
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ‍
*/

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.List;
import org.apache.commons.lang3.StringUtils;

public class LongListToStringSerializer extends JsonSerializer<List<Long>> {

@Override
public void serialize(List<Long> longs, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (longs != null) {
gen.writeString("{" + StringUtils.join(longs, ",") + "}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,23 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.Convert;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Type;
import org.springframework.data.domain.Persistable;

import com.hedera.mirror.importer.converter.AccountIdConverter;
import com.hedera.mirror.importer.converter.LongListToStringSerializer;
import com.hedera.mirror.importer.converter.TokenIdConverter;

@Data
Expand All @@ -46,6 +52,10 @@ public class AssessedCustomFee implements Persistable<AssessedCustomFee.Id> {

private long amount;

@Type(type = "com.vladmihalcea.hibernate.type.array.ListArrayType")
@JsonSerialize(using = LongListToStringSerializer.class)
private List<Long> effectivePayerAccountIds = Collections.emptyList();

@Convert(converter = TokenIdConverter.class)
private EntityId tokenId;

Expand All @@ -68,4 +78,10 @@ public static class Id implements Serializable {

private long consensusTimestamp;
}

public void setEffectivePayerEntityIds(List<EntityId> effectivePayerEntityIds) {
effectivePayerAccountIds = effectivePayerEntityIds.stream()
.map(AccountIdConverter.INSTANCE::convertToDatabaseColumn)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ public class CustomFee implements Persistable<CustomFee.Id> {

private long minimumAmount;

private Boolean netOfTransfers;

private Long royaltyDenominator;

private Long royaltyNumerator;

@JsonIgnore
@Override
public boolean isNew() {
Expand Down
Loading

0 comments on commit 014b1b6

Please sign in to comment.