Skip to content
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
425a132
initial support for token create
joshmarinacci Nov 3, 2025
000b26c
add tests for creating an NFT token
joshmarinacci Nov 5, 2025
540d4f1
add mint token test
joshmarinacci Nov 5, 2025
82af592
require keys for token mint
joshmarinacci Nov 5, 2025
1163058
add more mint cases
joshmarinacci Nov 6, 2025
ff3fcfe
adjust extras fees for tokens
joshmarinacci Nov 6, 2025
5b703a3
spotless
joshmarinacci Nov 6, 2025
9e3d418
adjust fee schedule
joshmarinacci Nov 13, 2025
d8a5c07
adjust prices
joshmarinacci Nov 14, 2025
2d36ca1
spotless
joshmarinacci Nov 14, 2025
100d0f7
mark as MATS
joshmarinacci Nov 14, 2025
3f0f5ae
fix TokenServicesFeeTests
joshmarinacci Nov 14, 2025
4a5e85e
update to new api
joshmarinacci Nov 19, 2025
44fd508
rename file
joshmarinacci Nov 19, 2025
6d9dcef
spotless
joshmarinacci Nov 19, 2025
0cfc2c5
initial support for token create
joshmarinacci Nov 3, 2025
fe83c9f
add tests for creating an NFT token
joshmarinacci Nov 5, 2025
51706e6
add mint token test
joshmarinacci Nov 5, 2025
b4a8c54
require keys for token mint
joshmarinacci Nov 5, 2025
d872a86
add more mint cases
joshmarinacci Nov 6, 2025
4ce9c7c
adjust extras fees for tokens
joshmarinacci Nov 6, 2025
86df183
spotless
joshmarinacci Nov 6, 2025
b58ed02
work on burn, delete, freeze, and pause
joshmarinacci Nov 12, 2025
310c604
move to calculator: token burn, token delete, token freeze, token unf…
joshmarinacci Nov 14, 2025
6970c43
spotless
joshmarinacci Nov 19, 2025
42334e1
spotless
joshmarinacci Nov 19, 2025
48618ec
revert code changes
joshmarinacci Nov 19, 2025
45f84bb
merge duplicate test files
joshmarinacci Nov 19, 2025
ed6f082
merge duplicate test files again
joshmarinacci Nov 19, 2025
d659dab
remove unneeded file
joshmarinacci Nov 19, 2025
5c7b60d
fix merge conflicts
joshmarinacci Dec 4, 2025
d0fe2ae
simplify
joshmarinacci Dec 4, 2025
987ef50
spotless
joshmarinacci Dec 4, 2025
8b4f4dd
fix compile issue
joshmarinacci Dec 4, 2025
61867a3
spotless
joshmarinacci Dec 4, 2025
0559d0e
remove unneeded extra
joshmarinacci Dec 4, 2025
e888a79
Merge branch 'main' into token-service-unique
joshmarinacci Dec 5, 2025
2b829cb
fix protobuf merge
joshmarinacci Dec 5, 2025
0537862
fix protobuf merge
joshmarinacci Dec 5, 2025
3471dd1
add comment
joshmarinacci Dec 5, 2025
df91516
Merge branch 'main' into token-service-unique
joshmarinacci Dec 8, 2025
d90eed3
Merge branch 'main' into token-service-unique
joshmarinacci Dec 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,10 @@ enum Extra {
CRYPTO_TRANSFER_BASE_FUNGIBLE_CUSTOM_FEES=19;
CRYPTO_TRANSFER_BASE_NFT_CUSTOM_FEES=20;
HOOK_EXECUTION=21;
TOKEN_CREATE_FUNGIBLE=22;
TOKEN_CREATE_NFT=23;
TOKEN_MINT_FUNGIBLE=24;
TOKEN_MINT_NFT=25;
CONSENSUS_CREATE_TOPIC_WITH_CUSTOM_FEE=26;
CONSENSUS_SUBMIT_MESSAGE_WITH_CUSTOM_FEE=27;
TOKEN_CREATE_WITH_CUSTOM_FEE=22;
TOKEN_MINT_NFT=23;
CONSENSUS_CREATE_TOPIC_WITH_CUSTOM_FEE=24;
CONSENSUS_SUBMIT_MESSAGE_WITH_CUSTOM_FEE=25;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@
{ "name": "CUSTOM_FEE", "fee": 0 },
{ "name": "GAS", "fee": 1 },
{ "name": "ALLOWANCES", "fee": 500000000 },
{ "name": "TOKEN_CREATE_FUNGIBLE", "fee": 9999000000 },
{ "name": "TOKEN_CREATE_NFT", "fee": 19999000000 },
{ "name": "TOKEN_MINT_FUNGIBLE", "fee": 0 },
{ "name": "TOKEN_CREATE_WITH_CUSTOM_FEE", "fee": 10000000000 },
{ "name": "TOKEN_MINT_NFT", "fee": 199000000 },
{ "name": "AIRDROPS", "fee": 8800 },
{ "name": "HOOK_UPDATES", "fee": 10000000000 },
Expand Down Expand Up @@ -185,18 +183,16 @@
"schedule": [
{
"name": "TokenCreate",
"baseFee": 0,
"baseFee": 9999000000,
"extras": [
{"name": "KEYS", "includedCount": 1},
{"name": "TOKEN_CREATE_FUNGIBLE", "includedCount": 0 },
{"name": "TOKEN_CREATE_NFT", "includedCount": 0 }
{"name": "TOKEN_CREATE_WITH_CUSTOM_FEE", "includedCount": 0 }
]
},
{
"name": "TokenMint",
"baseFee": 9000000,
"extras": [
{"name": "TOKEN_MINT_FUNGIBLE", "includedCount": 0 },
{"name": "TOKEN_MINT_NFT", "includedCount": 0 }
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import static org.hiero.hapi.fees.FeeScheduleUtils.lookupServiceFee;

import com.hedera.hapi.node.base.HederaFunctionality;
import com.hedera.hapi.node.base.TokenType;
import com.hedera.hapi.node.transaction.TransactionBody;
import com.hedera.node.app.spi.fees.FeeContext;
import com.hedera.node.app.spi.fees.ServiceFeeCalculator;
Expand Down Expand Up @@ -55,11 +54,8 @@ public void accumulateServiceFee(
}
addExtraFee(feeResult, serviceDef, Extra.KEYS, feeSchedule, keys);

if (op.tokenType() == TokenType.FUNGIBLE_COMMON) {
addExtraFee(feeResult, serviceDef, Extra.TOKEN_CREATE_FUNGIBLE, feeSchedule, 1);
}
if (op.tokenType() == TokenType.NON_FUNGIBLE_UNIQUE) {
addExtraFee(feeResult, serviceDef, Extra.TOKEN_CREATE_NFT, feeSchedule, 1);
if (!op.customFees().isEmpty()) {
addExtraFee(feeResult, serviceDef, Extra.TOKEN_CREATE_WITH_CUSTOM_FEE, feeSchedule, 1);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ public void accumulateServiceFee(
feeResult.addServiceFee(1, serviceDef.baseFee());
var op = txnBody.tokenMintOrThrow();
if (op.amount() > 0) {
addExtraFee(feeResult, serviceDef, Extra.TOKEN_MINT_FUNGIBLE, feeSchedule, op.amount());
addExtraFee(feeResult, serviceDef, Extra.TOKEN_MINT_NFT, feeSchedule, 0);
} else {
addExtraFee(feeResult, serviceDef, Extra.TOKEN_MINT_FUNGIBLE, feeSchedule, 0);
addExtraFee(
feeResult,
serviceDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ void createCommonToken() {
.build();
final var result = feeCalculator.calculateTxFee(body, calculatorState);
assertNotNull(result);
assertEquals(TOKEN_CREATE_BASE_FEE + COMMON_TOKEN_FEE, result.total());
assertEquals(TOKEN_CREATE_BASE_FEE, result.total());
}

@Test
Expand All @@ -118,7 +118,7 @@ void createUniqueToken() {
final var result = feeCalculator.calculateTxFee(txBody2, calculatorState);

assertNotNull(result);
assertEquals(TOKEN_CREATE_BASE_FEE + UNIQUE_TOKEN_FEE, result.total());
assertEquals(TOKEN_CREATE_BASE_FEE, result.total());
}

@Test
Expand All @@ -133,7 +133,7 @@ void mintCommonToken() {
.build();
final var result = feeCalculator.calculateTxFee(body, calculatorState);
assertNotNull(result);
assertEquals(TOKEN_MINT_BASE_FEE + COMMON_TOKEN_FEE * 10, result.total());
assertEquals(TOKEN_MINT_BASE_FEE, result.total());
}

@Test
Expand Down Expand Up @@ -242,25 +242,16 @@ private FeeSchedule createTestFeeSchedule() {
makeExtraDef(Extra.BYTES, 1),
makeExtraDef(Extra.KEYS, 2),
makeExtraDef(Extra.SIGNATURES, 3),
makeExtraDef(Extra.TOKEN_CREATE_FUNGIBLE, COMMON_TOKEN_FEE),
makeExtraDef(Extra.TOKEN_CREATE_NFT, UNIQUE_TOKEN_FEE),
makeExtraDef(Extra.TOKEN_MINT_FUNGIBLE, COMMON_TOKEN_FEE),
makeExtraDef(Extra.TOKEN_MINT_NFT, UNIQUE_TOKEN_FEE),
makeExtraDef(Extra.CUSTOM_FEE, 500))
.network(NetworkFee.DEFAULT.copyBuilder().multiplier(2).build())
.services(makeService(
"Token",
makeServiceFee(
TOKEN_CREATE,
TOKEN_CREATE_BASE_FEE,
makeExtraIncluded(Extra.KEYS, 1),
makeExtraIncluded(Extra.TOKEN_CREATE_FUNGIBLE, 0),
makeExtraIncluded(Extra.TOKEN_CREATE_NFT, 0)),
makeServiceFee(TOKEN_CREATE, TOKEN_CREATE_BASE_FEE, makeExtraIncluded(Extra.KEYS, 1)),
makeServiceFee(
TOKEN_MINT,
TOKEN_MINT_BASE_FEE,
makeExtraIncluded(Extra.KEYS, 1),
makeExtraIncluded(Extra.TOKEN_MINT_FUNGIBLE, 0),
makeExtraIncluded(Extra.TOKEN_MINT_NFT, 0)),
makeServiceFee(TOKEN_BURN, TOKEN_BURN_BASE_FEE),
makeServiceFee(TOKEN_DELETE, TOKEN_DELETE_BASE_FEE),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.tokenPause;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.tokenUnfreeze;
import static com.hedera.services.bdd.spec.transactions.TxnVerbs.tokenUnpause;
import static com.hedera.services.bdd.spec.transactions.token.CustomFeeSpecs.fixedHbarFee;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.compareSimpleToOld;
import static com.hedera.services.bdd.spec.utilops.UtilVerbs.newKeyNamed;
import static com.hedera.services.bdd.suites.HapiSuite.ONE_BILLION_HBARS;
Expand Down Expand Up @@ -45,6 +46,7 @@ public class TokenServiceSimpleFeesSuite {
private static final String PAYER = "payer";
private static final String ADMIN = "admin";
private static final String OTHER = "other";
private static final String HBAR_COLLECTOR = "hbarCollector";

@LeakyHapiTest(overrides = {"fees.simpleFeesEnabled"})
@DisplayName("compare create fungible token")
Expand Down Expand Up @@ -101,6 +103,36 @@ final Stream<DynamicTest> compareCreateNonFungibleToken() {
// fungible = 19999000000,
// node+network = 1000000
// total = 20000000000 = 2.0
1,
1,
1,
1);
}

@LeakyHapiTest(overrides = {"fees.simpleFeesEnabled"})
@DisplayName("compare create fungible token with custom fees")
final Stream<DynamicTest> compareCreateFungibleTokenWithCustomFees() {
return compareSimpleToOld(
() -> Arrays.asList(
newKeyNamed(SUPPLY_KEY),
cryptoCreate(ADMIN).balance(ONE_BILLION_HBARS),
cryptoCreate(PAYER).balance(ONE_BILLION_HBARS),
cryptoCreate(HBAR_COLLECTOR).balance(0L),
tokenCreate("commonCustomFees")
.blankMemo()
.payingWith(PAYER)
.fee(ONE_HUNDRED_HBARS)
.treasury(ADMIN)
.tokenType(NON_FUNGIBLE_UNIQUE)
.initialSupply(0L)
.supplyKey(SUPPLY_KEY)
.autoRenewAccount(ADMIN)
.autoRenewPeriod(THREE_MONTHS_IN_SECONDS)
.withCustom(fixedHbarFee(1L, HBAR_COLLECTOR))
.logged()
.hasKnownStatus(SUCCESS)
.via("create-token-txn")),
"create-token-txn",
2,
1,
2,
Expand Down
Loading