Search in sources :

Example 1 with CustomFee

use of com.hedera.mirror.common.domain.transaction.CustomFee in project hedera-mirror-node by hashgraph.

the class EntityRecordItemListener method insertCustomFees.

/**
 * Inserts custom fees. Returns the list of collectors automatically associated with the newly created token if the
 * custom fees are from a token create transaction
 *
 * @param customFeeList      protobuf custom fee list
 * @param consensusTimestamp consensus timestamp of the corresponding transaction
 * @param isTokenCreate      if the transaction with the custom fees is a token create
 * @param tokenId            the token id the custom fees are attached to
 * @return A list of collectors automatically associated with the token if it's a token create transaction
 */
private Set<EntityId> insertCustomFees(List<com.hederahashgraph.api.proto.java.CustomFee> customFeeList, long consensusTimestamp, boolean isTokenCreate, EntityId tokenId) {
    Set<EntityId> autoAssociatedAccounts = new HashSet<>();
    CustomFee.Id id = new CustomFee.Id(consensusTimestamp, tokenId);
    for (var protoCustomFee : customFeeList) {
        EntityId collector = EntityId.of(protoCustomFee.getFeeCollectorAccountId());
        CustomFee customFee = new CustomFee();
        customFee.setId(id);
        customFee.setCollectorAccountId(collector);
        var feeCase = protoCustomFee.getFeeCase();
        boolean chargedInAttachedToken;
        switch(feeCase) {
            case FIXED_FEE:
                chargedInAttachedToken = parseFixedFee(customFee, protoCustomFee.getFixedFee(), tokenId);
                break;
            case FRACTIONAL_FEE:
                // only FT can have fractional fee
                parseFractionalFee(customFee, protoCustomFee.getFractionalFee());
                chargedInAttachedToken = true;
                break;
            case ROYALTY_FEE:
                // only NFT can have royalty fee, and fee can't be paid in NFT. Thus though royalty fee has a
                // fixed fee fallback, the denominating token of the fixed fee can't be the NFT itself
                parseRoyaltyFee(customFee, protoCustomFee.getRoyaltyFee(), tokenId);
                chargedInAttachedToken = false;
                break;
            default:
                log.error("Invalid CustomFee FeeCase {}", feeCase);
                throw new InvalidDatasetException(String.format("Invalid CustomFee FeeCase %s", feeCase));
        }
        if (isTokenCreate && chargedInAttachedToken) {
            // if it's from a token create transaction, and the fee is charged in the attached token, the attached
            // token and the collector should have been auto associated
            autoAssociatedAccounts.add(collector);
        }
        entityListener.onCustomFee(customFee);
    }
    if (customFeeList.isEmpty()) {
        // for empty custom fees, add a single row with only the timestamp and tokenId.
        CustomFee customFee = new CustomFee();
        customFee.setId(id);
        entityListener.onCustomFee(customFee);
    }
    return autoAssociatedAccounts;
}
Also used : EntityId(com.hedera.mirror.common.domain.entity.EntityId) CustomFee(com.hedera.mirror.common.domain.transaction.CustomFee) AssessedCustomFee(com.hedera.mirror.common.domain.transaction.AssessedCustomFee) InvalidDatasetException(com.hedera.mirror.importer.exception.InvalidDatasetException) EntityId(com.hedera.mirror.common.domain.entity.EntityId) TokenId(com.hedera.mirror.common.domain.token.TokenId) NftTransferId(com.hedera.mirror.common.domain.token.NftTransferId) HashSet(java.util.HashSet)

Example 2 with CustomFee

use of com.hedera.mirror.common.domain.transaction.CustomFee in project hedera-mirror-node by hashgraph.

the class EntityRecordItemListenerTokenTest method deletedDbCustomFees.

private static List<CustomFee> deletedDbCustomFees(long consensusTimestamp, EntityId tokenId) {
    CustomFee customFee = new CustomFee();
    customFee.setId(new CustomFee.Id(consensusTimestamp, tokenId));
    return List.of(customFee);
}
Also used : CustomFee(com.hedera.mirror.common.domain.transaction.CustomFee) AssessedCustomFee(com.hedera.mirror.common.domain.transaction.AssessedCustomFee)

Example 3 with CustomFee

use of com.hedera.mirror.common.domain.transaction.CustomFee in project hedera-mirror-node by hashgraph.

the class EntityRecordItemListenerTokenTest method nonEmptyCustomFees.

private static List<CustomFee> nonEmptyCustomFees(long consensusTimestamp, EntityId tokenId, TokenType tokenType) {
    List<CustomFee> customFees = new ArrayList<>();
    CustomFee.Id id = new CustomFee.Id(consensusTimestamp, tokenId);
    EntityId treasury = EntityId.of(PAYER);
    CustomFee fixedFee1 = new CustomFee();
    fixedFee1.setAmount(11L);
    fixedFee1.setCollectorAccountId(FEE_COLLECTOR_ACCOUNT_ID_1);
    fixedFee1.setId(id);
    customFees.add(fixedFee1);
    CustomFee fixedFee2 = new CustomFee();
    fixedFee2.setAmount(12L);
    fixedFee2.setCollectorAccountId(FEE_COLLECTOR_ACCOUNT_ID_2);
    fixedFee2.setDenominatingTokenId(FEE_DOMAIN_TOKEN_ID);
    fixedFee2.setId(id);
    customFees.add(fixedFee2);
    CustomFee fixedFee3 = new CustomFee();
    fixedFee3.setAmount(13L);
    fixedFee3.setCollectorAccountId(FEE_COLLECTOR_ACCOUNT_ID_2);
    fixedFee3.setDenominatingTokenId(tokenId);
    fixedFee3.setId(id);
    customFees.add(fixedFee3);
    if (tokenType == FUNGIBLE_COMMON) {
        // fractional fees only apply for fungible tokens
        CustomFee fractionalFee1 = new CustomFee();
        fractionalFee1.setAmount(14L);
        fractionalFee1.setAmountDenominator(31L);
        fractionalFee1.setCollectorAccountId(FEE_COLLECTOR_ACCOUNT_ID_3);
        fractionalFee1.setMaximumAmount(100L);
        fractionalFee1.setNetOfTransfers(true);
        fractionalFee1.setId(id);
        customFees.add(fractionalFee1);
        CustomFee fractionalFee2 = new CustomFee();
        fractionalFee2.setAmount(15L);
        fractionalFee2.setAmountDenominator(32L);
        fractionalFee2.setCollectorAccountId(treasury);
        fractionalFee2.setMaximumAmount(110L);
        fractionalFee2.setNetOfTransfers(false);
        fractionalFee2.setId(id);
        customFees.add(fractionalFee2);
    } else {
        // royalty fees only apply for non-fungible tokens
        CustomFee royaltyFee1 = new CustomFee();
        royaltyFee1.setRoyaltyNumerator(14L);
        royaltyFee1.setRoyaltyDenominator(31L);
        royaltyFee1.setCollectorAccountId(FEE_COLLECTOR_ACCOUNT_ID_3);
        royaltyFee1.setId(id);
        customFees.add(royaltyFee1);
        // with fallback fee
        CustomFee royaltyFee2 = new CustomFee();
        royaltyFee2.setRoyaltyNumerator(15L);
        royaltyFee2.setRoyaltyDenominator(32L);
        royaltyFee2.setCollectorAccountId(treasury);
        // fallback fee in form of fixed fee
        royaltyFee2.setAmount(103L);
        royaltyFee2.setDenominatingTokenId(FEE_DOMAIN_TOKEN_ID);
        royaltyFee2.setId(id);
        customFees.add(royaltyFee2);
    }
    return customFees;
}
Also used : EntityId(com.hedera.mirror.common.domain.entity.EntityId) CustomFee(com.hedera.mirror.common.domain.transaction.CustomFee) AssessedCustomFee(com.hedera.mirror.common.domain.transaction.AssessedCustomFee) ArrayList(java.util.ArrayList) EntityId(com.hedera.mirror.common.domain.entity.EntityId) TokenId(com.hedera.mirror.common.domain.token.TokenId) NftTransferId(com.hedera.mirror.common.domain.token.NftTransferId) NftId(com.hedera.mirror.common.domain.token.NftId) TokenAccountId(com.hedera.mirror.common.domain.token.TokenAccountId)

Example 4 with CustomFee

use of com.hedera.mirror.common.domain.transaction.CustomFee in project hedera-mirror-node by hashgraph.

the class EntityRecordItemListenerTokenTest method provideTokenCreateArguments.

private static Stream<Arguments> provideTokenCreateArguments(TokenType tokenType) {
    List<CustomFee> nonEmptyCustomFees = nonEmptyCustomFees(CREATE_TIMESTAMP, DOMAIN_TOKEN_ID, tokenType);
    EntityId treasury = EntityId.of(PAYER);
    // fractional fees only apply for FT, thus FEE_COLLECTOR_ACCOUNT_ID_3 (collector of a fractional fee for FT, and
    // a royalty fee in case of NFT) will be auto enabled only for FT custom fees
    List<EntityId> autoEnabledAccounts = tokenType == FUNGIBLE_COMMON ? List.of(treasury, FEE_COLLECTOR_ACCOUNT_ID_2, FEE_COLLECTOR_ACCOUNT_ID_3) : List.of(treasury, FEE_COLLECTOR_ACCOUNT_ID_2);
    return Stream.of(TokenCreateArguments.builder().autoEnabledAccounts(List.of(treasury)).createdTimestamp(CREATE_TIMESTAMP).customFees(deletedDbCustomFees(CREATE_TIMESTAMP, DOMAIN_TOKEN_ID)).customFeesDescription("empty custom fees").tokenId(DOMAIN_TOKEN_ID).build().toArguments(), TokenCreateArguments.builder().autoEnabledAccounts(autoEnabledAccounts).createdTimestamp(CREATE_TIMESTAMP).customFees(nonEmptyCustomFees).customFeesDescription("non-empty custom fees").freezeKey(true).freezeStatus(TokenFreezeStatusEnum.UNFROZEN).tokenId(DOMAIN_TOKEN_ID).build().toArguments(), TokenCreateArguments.builder().autoEnabledAccounts(autoEnabledAccounts).createdTimestamp(CREATE_TIMESTAMP).customFees(nonEmptyCustomFees).customFeesDescription("non-empty custom fees").freezeDefault(true).freezeKey(true).freezeStatus(TokenFreezeStatusEnum.UNFROZEN).tokenId(DOMAIN_TOKEN_ID).build().toArguments(), TokenCreateArguments.builder().autoEnabledAccounts(autoEnabledAccounts).createdTimestamp(CREATE_TIMESTAMP).customFees(nonEmptyCustomFees).customFeesDescription("non-empty custom fees").kycKey(true).kycStatus(TokenKycStatusEnum.GRANTED).tokenId(DOMAIN_TOKEN_ID).build().toArguments(), TokenCreateArguments.builder().autoEnabledAccounts(autoEnabledAccounts).createdTimestamp(CREATE_TIMESTAMP).customFees(nonEmptyCustomFees).customFeesDescription("non-empty custom fees").tokenId(DOMAIN_TOKEN_ID).build().toArguments(), TokenCreateArguments.builder().autoEnabledAccounts(autoEnabledAccounts).createdTimestamp(CREATE_TIMESTAMP).customFees(nonEmptyCustomFees).customFeesDescription("non-empty custom fees").pauseKey(true).tokenId(DOMAIN_TOKEN_ID).build().toArguments());
}
Also used : EntityId(com.hedera.mirror.common.domain.entity.EntityId) CustomFee(com.hedera.mirror.common.domain.transaction.CustomFee) AssessedCustomFee(com.hedera.mirror.common.domain.transaction.AssessedCustomFee)

Example 5 with CustomFee

use of com.hedera.mirror.common.domain.transaction.CustomFee in project hedera-mirror-node by hashgraph.

the class EntityRecordItemListenerTokenTest method tokenFeeScheduleUpdate.

@ParameterizedTest(name = "{0}")
@EnumSource(value = TokenType.class, names = { "FUNGIBLE_COMMON", "NON_FUNGIBLE_UNIQUE" })
void tokenFeeScheduleUpdate(TokenType tokenType) {
    // given
    // create the token entity with empty custom fees
    createTokenEntity(TOKEN_ID, tokenType, SYMBOL, CREATE_TIMESTAMP, false, false, false);
    // update fee schedule
    long updateTimestamp = CREATE_TIMESTAMP + 10L;
    Entity expectedEntity = createEntity(DOMAIN_TOKEN_ID, TOKEN_REF_KEY, PAYER.getAccountNum(), AUTO_RENEW_PERIOD, false, EXPIRY_NS, TOKEN_CREATE_MEMO, null, CREATE_TIMESTAMP, CREATE_TIMESTAMP);
    List<CustomFee> newCustomFees = nonEmptyCustomFees(updateTimestamp, DOMAIN_TOKEN_ID, tokenType);
    List<CustomFee> expectedCustomFees = Lists.newArrayList(deletedDbCustomFees(CREATE_TIMESTAMP, DOMAIN_TOKEN_ID));
    expectedCustomFees.addAll(newCustomFees);
    long expectedSupply = tokenType == FUNGIBLE_COMMON ? INITIAL_SUPPLY : 0;
    // when
    updateTokenFeeSchedule(TOKEN_ID, updateTimestamp, newCustomFees);
    // then
    assertEntity(expectedEntity);
    assertTokenInRepository(TOKEN_ID, true, CREATE_TIMESTAMP, CREATE_TIMESTAMP, SYMBOL, expectedSupply);
    assertCustomFeesInDb(expectedCustomFees);
}
Also used : Entity(com.hedera.mirror.common.domain.entity.Entity) CustomFee(com.hedera.mirror.common.domain.transaction.CustomFee) AssessedCustomFee(com.hedera.mirror.common.domain.transaction.AssessedCustomFee) EnumSource(org.junit.jupiter.params.provider.EnumSource) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Aggregations

AssessedCustomFee (com.hedera.mirror.common.domain.transaction.AssessedCustomFee)5 CustomFee (com.hedera.mirror.common.domain.transaction.CustomFee)5 EntityId (com.hedera.mirror.common.domain.entity.EntityId)3 NftTransferId (com.hedera.mirror.common.domain.token.NftTransferId)2 TokenId (com.hedera.mirror.common.domain.token.TokenId)2 Entity (com.hedera.mirror.common.domain.entity.Entity)1 NftId (com.hedera.mirror.common.domain.token.NftId)1 TokenAccountId (com.hedera.mirror.common.domain.token.TokenAccountId)1 InvalidDatasetException (com.hedera.mirror.importer.exception.InvalidDatasetException)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)1 EnumSource (org.junit.jupiter.params.provider.EnumSource)1