Hedera
Ask or search…
K

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

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.
Constructor
Description
new CustomFixedFee()
Initializes the CustomFixedFee object
new CustomFixedFee()
Methods
Description
Type
Requirement
setFeeCollectorAccountId
Sets the fee collector account ID that collects the fee.
AccountId
Required
setHbarAmount
Set the amount of HBAR to be collected.
HBAR
Optional
setAmount
Sets the amount of tokens to be collected as the fee.
int64
Optional
setDenominatingTokenId
The ID of the token used to charge the fee. The denomination of the fee is taken as HBAR if left unset.
TokenID
Optional
setAllCollectorsAreExempt
If true, exempts all the token's fee collector accounts from this fee.
boolean
Optional
Java
JavaScript
Go
//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
//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
//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

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.
Methods
Description
Type
Requirement
setFeeCollectorAccountId
Sets the fee collector account ID that collects the fee.
AccountId
Required
setNumerator
Sets the numerator of the fraction.
long
Required
setDenominator
Sets the denominator of the fraction. Cannot be zero.
long
Required
setMax
The maximum fee that can be charged, regardless of the fractional value.
long
Optional
setMin
The minimum fee that can be charged, regardless of the fractional value.
long
Optional
setAssessmentMethod
If true, sender pays fees and the receiver collects the full token transfer amount. If false, receiver pays fees and gets remaining token balance.
boolean
Optional
setAllCollectorsAreExempt
If true, exempts all the token's fee collector accounts from this fee.
boolean
Optional
Java
JavaScript
Go
//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
//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
//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

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.
🔔 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.
Constructor
Description
new CustomRoyaltyFee()
Initializes the CustomRoyaltyFee object
new CustomRoyaltyFee()
Methods
Description
Type
Requirement
setFeeCollectorAccountId
Sets the fee collector account ID that collects the fee.
AccountId
Required
setNumerator
Sets the numerator of the fraction.
long
Required
setDenominator
Sets the denominator of the fraction.
long
Required
setFallbackFee
If present, the fixed fee to assess to the NFT receiver when no fungible value is exchanged with the sender
FixedFee
Optional
setAllCollectorsAreExempt
If true, exempts all the token's fee collector accounts from this fee.
boolean
Optional
Java
JavaScript
Go
//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
//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
//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

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.