Skip to content

Latest commit

 

History

History
205 lines (155 loc) · 14.6 KB

custom-token-fees.md

File metadata and controls

205 lines (155 loc) · 14.6 KB

Custom token fees

When creating a token, you can configure up to 10 custom fees, automatically disbursed to specified fee collector accounts each time the token is transferred programmatically. These fees can be fixed, fractional, or royalty-based, offering revenue generation, profit-sharing, and behavior incentivization for creators. This guide is your comprehensive resource for understanding types, implementation, and best practices for custom fees on Hedera.


Types of Custom Fees

Fixed Fee: Paid by the sender of the fungible or non-fungible tokens. A fixed fee transfers a set amount to a fee collector account each time a token is transferred, independent of the transfer size. This fee can be collected in HBAR or another Hedera token but not in NFTs.

Fractional Fee: Take a specific portion of the transferred fungible tokens, with optional minimum and maximum limits. The token receiver (fee collector account) pays these fees by default. However, if net_of_transfers is set to true, the sender pays the fees and the receiver collects the full token transfer amount. If this field is set to false, the receiver pays for the token custom fees and gets the remaining token balance.

Royalty Fee: Paid by the receiver account that is exchanging the fungible value for the NFT. When the NFT sender does not receive any fungible value, the fallback fee is charged to the NFT receiver.

{% hint style="info" %} Note: In addition to the custom token fee payment, the sender account must pay for the token transfer transaction fee in HBAR. The "Payment of Custom Fees & Transaction Fees in HBAR" section below covers the distinction between custom fees and transaction fees. {% endhint %}


Implementation Methods

Fixed Fee

A fixed fee entails transferring a specified token amount to predefined fee collector accounts each time a token transfer is initiated. This fee amount doesn't depend on the volume of tokens being transferred. The creator has the flexibility to collect the fee in HBAR or another fungible Hedera token. However, it's important to note that NFTs cannot be used as a token type to collect this fee. A custom fixed fee can be set for fungible and non-fungible token types.

ConstructorDescription
new CustomFixedFee()Initializes the CustomFixedFee object
new CustomFixedFee()
MethodsDescriptionTypeRequirement
setFeeCollectorAccountIdSets the fee collector account ID that collects the fee.AccountIdRequired
setHbarAmountSet the amount of HBAR to be collected.HBAROptional
setAmountSets the amount of tokens to be collected as the fee.int64Optional
setDenominatingTokenIdThe ID of the token used to charge the fee. The denomination of the fee is taken as HBAR if left unset.TokenIDOptional
setAllCollectorsAreExemptIf true, exempts all the token's fee collector accounts from this fee.booleanOptional

{% tabs %} {% tab title="Java" %}

//Create a custom token fixed fee
new CustomFixedFee()
    .setAmount(1) // 1 token is transferred to the fee collecting account each time this token is transferred
    .setDenominatingTokenId(tokenId) // The token to charge the fee in 
    .setFeeCollectorAccountId(feeCollectorAccountId); // 1 token is sent to this account everytime it is transferred

//Version: 2.0.143

{% endtab %}

{% tab title="JavaScript" %}

//Create a custom token fixed fee
new CustomFixedFee()
    .setAmount(1) // 1 token is transferred to the fee collecting account each time this token is transferred
    .setDenominatingTokenId(tokenId) // The token to charge the fee in
    .setFeeCollectorAccountId(feeCollectorAccountId); // 1 token is sent to this account everytime it is transferred

//Version: 2.0.30

{% endtab %}

{% tab title="Go" %}

//Create a custom token fixed fee
[]hedera.Fee{
		hedera.NewCustomFixedFee().
		SetAmount(1). // 1 token is transferred to the fee collecting account each time this token is transferred
		SetDenominatingTokenID(tokenId). // The token to charge the fee in 
		SetFeeCollectorAccountID(feeCollectorAccountId) // 1 token is sent to this account everytime it is transferred
   },
}
//Version: 2.1.16

{% endtab %} {% endtabs %}

Fractional Fee

Fractional fees involve the transfer of a specified fraction of the tokens' total value to the designated fee collector account. You can set a custom fractional fee and impose minimum and maximum fee limits per transfer transaction. The fractional fee has to be less than or equal to 1. It cannot exceed the fractional range of a 64-bit signed integer. Applicable to fungible tokens only.

MethodsDescriptionTypeRequirementType
setFeeCollectorAccountIdSets the fee collector account ID that collects the fee.AccountIdRequiredAccountId
setNumeratorSets the numerator of the fraction.longRequiredlong
setDenominatorSets the denominator of the fraction. Cannot be zero.longRequiredlong
setMaxThe maximum fee that can be charged, regardless of the fractional value.longOptionallong
setMinThe minimum fee that can be charged, regardless of the fractional value.longOptionallong
setAssessmentMethodIf true, sender pays fees and the receiver collects the full token transfer amount. If false, receiver pays fees and gets remaining token balance.booleanOptionalFeeAssessmentMethod
setAllCollectorsAreExemptIf true, exempts all the token's fee collector accounts from this fee.booleanOptionalboolean

{% tabs %} {% tab title="Java" %}

//Create a custom token fractional fee
new CustomFractionalFee()
    .setNumerator(1) // The numerator of the fraction
    .setDenominator(10) // The denominator of the fraction
    .setFeeCollectorAccountId(feeCollectorAccountId); // The account collecting the 10% custom fee each time the token is transferred

//Version: 2.0.14

{% endtab %}

{% tab title="JavaScript" %}

//Create a custom token fractional fee
new CustomFractionalFee()
    .setNumerator(1) // The numerator of the fraction
    .setDenominator(10) // The denominator of the fraction
    .setFeeCollectorAccountId(feeCollectorAccountId); // The account collecting the 10% custom fee each time the token is transferred

//Version: 2.0.30    

{% endtab %}

{% tab title="Go" %}

//Create a custom token fractional fee
[]hedera.Fee{
		hedera.NewCustomFractionalFee().
		SetNumerator(1). // The numerator of the fraction
		SetDenominator(10). // The denominator of the fraction
		SetFeeCollectorAccountID(feeCollectorAccountId), // The account collecting the 10% custom fee each time the token is transferred
	}

//Version: 2.1.16

{% endtab %} {% endtabs %}

Royalty Fee

The royalty fee is assessed and applied each time the ownership of an NFT is transferred and is a fraction of the value exchanged for the NFT. If no value is exchanged for the NFT, a fallback fee can be imposed on the receiving account. This fee type only applies to non-fungible tokens.

{% hint style="info" %} 🔔 NOTE: Royalty fees are strictly a convenience feature. The network can't enforce royalties if counterparties decide to split their NFT exchange into separate transactions. The NFT sender and receiver must both sign a single CryptoTransfer to ensure the proper application of royalties. There is an open HIP discussion about broadening the class of transactions for which the network automatically collects royalties. If this topic interests or concerns you, your participation in the discussion is welcome. {% endhint %}

ConstructorDescription
new CustomRoyaltyFee()Initializes the CustomRoyaltyFee object
new CustomRoyaltyFee()
MethodsDescriptionTypeRequirement
setFeeCollectorAccountIdSets the fee collector account ID that collects the fee.AccountIdRequired
setNumeratorSets the numerator of the fraction.longRequired
setDenominatorSets the denominator of the fraction.longRequired
setFallbackFeeIf present, the fixed fee to assess to the NFT receiver when no fungible value is exchanged with the senderFixedFeeOptional
setAllCollectorsAreExemptIf true, exempts all the token's fee collector accounts from this fee.booleanOptional

{% tabs %} {% tab title="Java" %}

//Create a royalty fee
new CustomRoyaltyFee()
     .setNumerator(1) // The numerator of the fraction
     .setDenominator(10) // The denominator of the fraction
     .setFallbackFee(new CustomFixedFee().setHbarAmount(new Hbar(1)) // The fallback fee
     .setFeeCollectorAccountId(feeCollectorAccountId))) // The account that will receive the royalty fee

// v2.0.14 

{% endtab %}

{% tab title="JavaScript" %}

//Create a royalty fee
new CustomRoyaltyFee()
     .setNumerator(1) // The numerator of the fraction
     .setDenominator(10) // The denominator of the fraction
     .setFallbackFee(new CustomFixedFee().setHbarAmount(new Hbar(1)) // The fallback fee
     .setFeeCollectorAccountId(feeCollectorAccountId))) // The account that will receive the royalty fee
     
 // v2.0.30 

{% endtab %}

{% tab title="Go" %}

//Create a royalty fee 
[]hedera.Fee{
		hedera.NewCustomRoyaltyFee().
		SetFeeCollectorAccountID(feeCollectorAccountId). // The account that will receive the royalty fee
		SetNumerator(1). // The numerator of the fraction
		SetDenominator(10). // The denominator of the fraction
		SetFallbackFee( // The fallback fee
			hedera.NewCustomFixedFee().
			SetFeeCollectorAccountID(feeCollectorAccountId).
			SetAmount(1),
		),
	}
	
// v2.1.16

{% endtab %} {% endtabs %}


Payment of Custom Fees vs. Transaction Fees in HBAR

Understanding the difference between custom fees and standard transaction fees in HBAR is crucial for token issuers and developers working with Hedera. Custom fees are designed to enforce complex fee structures, such as royalties and fractional ownership. These fees ca n be fixed, fractional, or royalty-based and are usually paid in the token being transferred, although other Hedera tokens or HBAR can also be used. You can configure up to 10 custom fees automatically disbursed to designated fee collector accounts.

On the other hand, transaction fees in HBAR serve a different purpose: they compensate network nodes for processing transactions. These fees are uniform across all transaction types and are paid exclusively in HBAR. Unlike custom fees, which can be configured by the user, transaction fees are fixed by the network.

The key differences lie in their flexibility, payee, currency, and configurability. Custom fees offer greater flexibility and can be paid to any account in various tokens, and are user-defined. Transaction fees are network-defined, less flexible, and go solely to network nodes, paid only in HBAR.

Fee Exemptions

Fee collector accounts can be exempt from paying custom fees. To enable this, you need to set the exemption during the creation of the custom fees (HIP-573). If not enabled, custom fees will only be exempt for an account if that account is set as a fee collector.

Limits and Constraints

When it comes to setting custom fees, there are a few limits and constraints to keep in mind:

  • First, fees cannot be set to a negative value.
  • Each token can have up to 10 different custom fees.
  • Additionally, the treasury account for a given token is automatically exempt from paying these custom transaction fees.
  • The system also permits, at most, two "levels" of custom fees. That means a token being transferred might require fees in another token that also has its own fee schedule; however, this can only be nested two layers deep to prevent excessive complexity.