Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ jobs:
uses: hiero-ledger/hiero-solo-action@a39acf8cfbaa2feb195a86530d0ab643a45aa541 # v0.10.0
with:
installMirrorNode: true
hieroVersion: v0.64.2-rc1
mirrorNodeVersion: v0.134.0
hieroVersion: v0.65.0
mirrorNodeVersion: v0.136.1

- name: Set Operator Account
if: success() && matrix.test-type == 'e2e'
Expand Down Expand Up @@ -176,8 +176,8 @@ jobs:
uses: hiero-ledger/hiero-solo-action@a39acf8cfbaa2feb195a86530d0ab643a45aa541 # v0.10.0
with:
installMirrorNode: true
hieroVersion: v0.64.2-rc1
mirrorNodeVersion: v0.134.0
hieroVersion: v0.65.0
mirrorNodeVersion: v0.136.1

- name: Set Operator Account
run: |
Expand Down Expand Up @@ -228,4 +228,4 @@ jobs:

- name: Test TCK
run: go test ./...
working-directory: ./tck
working-directory: ./tck
281 changes: 281 additions & 0 deletions sdk/revenue-generating_topics_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -853,3 +853,284 @@

assert.True(t, accountBalance.Tokens.Get(tokenId) == 1)
}

func TestIntegrationRevenueGeneratingTopicCanChargeHbarsWithLimitSchedule(t *testing.T) {
t.Parallel()
env := NewIntegrationTestEnv(t)
defer CloseIntegrationTestEnv(env, nil)

var hbar int64 = 100_000_000
customFee := NewCustomFixedFee().
SetAmount(hbar / 2).
SetFeeCollectorAccountID(env.Client.GetOperatorAccountID())

// Create a revenue generating topic with Hbar custom fee
resp, err := NewTopicCreateTransaction().
SetAdminKey(env.Client.GetOperatorPublicKey()).
SetFeeScheduleKey(env.Client.GetOperatorPublicKey()).
AddCustomFee(customFee).
Execute(env.Client)
require.NoError(t, err)

receipt, err := resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

topicID := *receipt.TopicID
assert.NotNil(t, topicID)

// Create payer with 1 Hbar
payerId, payerPrivateKey, err := createAccount(&env)
require.NoError(t, err)

customFeeLimit := NewCustomFeeLimit().
SetPayerId(payerId).
AddCustomFee(NewCustomFixedFee().SetAmount(hbar))

// Submit a message to the revenue generating topic with custom fee limit
env.Client.SetOperator(payerId, payerPrivateKey)
schedule, err := NewTopicMessageSubmitTransaction().
SetMessage("message").
SetTopicID(topicID).
AddCustomFeeLimit(customFeeLimit).
Schedule()
require.NoError(t, err)

resp, err = schedule.Execute(env.Client)
require.NoError(t, err)

_, err = resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

env.Client.SetOperator(env.OperatorID, env.OperatorKey)

// Verify the custom fee charged
accountInfo, err := NewAccountInfoQuery().
SetAccountID(payerId).
Execute(env.Client)
require.NoError(t, err)

assert.True(t, accountInfo.Balance.AsTinybar() < hbar/2)
}

func TestIntegrationRevenueGeneratingTopicCanotChargeHbarsWithLowerLimitSchedule(t *testing.T) {
t.Parallel()
env := NewIntegrationTestEnv(t)
defer CloseIntegrationTestEnv(env, nil)

var hbar int64 = 100_000_000
customFee := NewCustomFixedFee().
SetAmount(hbar / 2).
SetFeeCollectorAccountID(env.Client.GetOperatorAccountID())

// Create a revenue generating topic with Hbar custom fee
resp, err := NewTopicCreateTransaction().
SetAdminKey(env.Client.GetOperatorPublicKey()).
SetFeeScheduleKey(env.Client.GetOperatorPublicKey()).
AddCustomFee(customFee).
Execute(env.Client)
require.NoError(t, err)

receipt, err := resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

topicID := *receipt.TopicID
assert.NotNil(t, topicID)

// Create payer with 1 Hbar
payerId, payerPrivateKey, err := createAccount(&env)
require.NoError(t, err)

// Set custom fee limit with lower amount than the custom fee
customFeeLimit := NewCustomFeeLimit().
SetPayerId(payerId).
AddCustomFee(NewCustomFixedFee().SetAmount((hbar / 2) - 1))

// Submit a message to the revenue generating topic with custom fee limit - fails with INSUFFICIENT_CUSTOM_FEE
env.Client.SetOperator(payerId, payerPrivateKey)
schedule, err := NewTopicMessageSubmitTransaction().
SetMessage("message").
SetTopicID(topicID).
AddCustomFeeLimit(customFeeLimit).
Schedule()
require.NoError(t, err)

resp, err = schedule.Execute(env.Client)
require.NoError(t, err)

_, err = resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

env.Client.SetOperator(env.OperatorID, env.OperatorKey)
// Verify the custom fee did not charge
accountInfo, err := NewAccountInfoQuery().
SetAccountID(payerId).
Execute(env.Client)
require.NoError(t, err)

assert.True(t, accountInfo.Balance.AsTinybar() > hbar/2)
}

func TestIntegrationRevenueGeneratingTopicCannotExecuteWithInvalidCustomFeeLimitSchedule(t *testing.T) {

Check warning on line 973 in sdk/revenue-generating_topics_e2e_test.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

sdk/revenue-generating_topics_e2e_test.go#L973

Method TestIntegrationRevenueGeneratingTopicCannotExecuteWithInvalidCustomFeeLimitSchedule has 70 lines of code (limit is 50)
t.Parallel()
env := NewIntegrationTestEnv(t)
defer CloseIntegrationTestEnv(env, nil)

tokenId, err := createFungibleToken(&env)
require.NoError(t, err)

customFee := NewCustomFixedFee().
SetAmount(2).
SetDenominatingTokenID(tokenId).
SetFeeCollectorAccountID(env.Client.GetOperatorAccountID())

// Create a revenue generating topic with token custom fee
resp, err := NewTopicCreateTransaction().
SetAdminKey(env.Client.GetOperatorPublicKey()).
SetFeeScheduleKey(env.Client.GetOperatorPublicKey()).
AddCustomFee(customFee).
Execute(env.Client)
require.NoError(t, err)

receipt, err := resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

topicID := *receipt.TopicID
assert.NotNil(t, topicID)

// Create payer with unlimited token associations
payerId, payerPrivateKey, err := createAccount(&env, func(transaction *AccountCreateTransaction) {
transaction.SetMaxAutomaticTokenAssociations(-1)
})
require.NoError(t, err)

// Send tokens to payer
resp, err = NewTransferTransaction().
AddTokenTransfer(tokenId, env.Client.GetOperatorAccountID(), -2).
AddTokenTransfer(tokenId, payerId, 2).
Execute(env.Client)
require.NoError(t, err)

_, err = resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

// Set custom fee limit with invalid token Id
customFeeLimit := NewCustomFeeLimit().
SetPayerId(payerId).
AddCustomFee(NewCustomFixedFee().SetAmount(2).SetDenominatingTokenID(TokenID{Token: 0}))

// Submit a message to the revenue generating topic - fails with NO_VALID_MAX_CUSTOM_FEE
env.Client.SetOperator(payerId, payerPrivateKey)
schedule, err := NewTopicMessageSubmitTransaction().
SetMessage("message").
SetTopicID(topicID).
AddCustomFeeLimit(customFeeLimit).
Schedule()
require.NoError(t, err)

resp, err = schedule.Execute(env.Client)
require.NoError(t, err)

_, err = resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

env.Client.SetOperator(env.OperatorID, env.OperatorKey)
// Verify the custom fee did not charge
accountInfo, err := NewAccountInfoQuery().
SetAccountID(payerId).
Execute(env.Client)
require.NoError(t, err)

var hbar int64 = 100_000_000
assert.True(t, accountInfo.Balance.AsTinybar() > hbar/2)

// Set custom fee limit with duplicate denomination token Id
customFeeLimit = NewCustomFeeLimit().
SetPayerId(payerId).
AddCustomFee(NewCustomFixedFee().SetAmount(1).SetDenominatingTokenID(tokenId)).
AddCustomFee(NewCustomFixedFee().SetAmount(2).SetDenominatingTokenID(tokenId))

// Submit a message to the revenue generating topic - fails with DUPLICATE_DENOMINATION_IN_MAX_CUSTOM_FEE_LIST
env.Client.SetOperator(payerId, payerPrivateKey)
schedule, err = NewTopicMessageSubmitTransaction().
SetMessage("message").
SetTopicID(topicID).
AddCustomFeeLimit(customFeeLimit).
Schedule()
require.NoError(t, err)

resp, err = schedule.Execute(env.Client)
require.NoError(t, err)

_, err = resp.SetValidateStatus(true).GetReceipt(env.Client)

env.Client.SetOperator(env.OperatorID, env.OperatorKey)
// Verify the custom fee did not charge
accountInfo, err = NewAccountInfoQuery().
SetAccountID(payerId).
Execute(env.Client)
require.NoError(t, err)
}

func TestIntegrationRevenueGeneratingTopicGetScheduledTransactionCustomFeeLimits(t *testing.T) {
t.Parallel()
env := NewIntegrationTestEnv(t)
defer CloseIntegrationTestEnv(env, nil)

var hbar int64 = 100_000_000
customFee := NewCustomFixedFee().
SetAmount(hbar / 2).
SetFeeCollectorAccountID(env.Client.GetOperatorAccountID())

// Create a revenue generating topic with Hbar custom fee
resp, err := NewTopicCreateTransaction().
SetAdminKey(env.Client.GetOperatorPublicKey()).
SetFeeScheduleKey(env.Client.GetOperatorPublicKey()).
AddCustomFee(customFee).
Execute(env.Client)
require.NoError(t, err)

receipt, err := resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

topicID := *receipt.TopicID
assert.NotNil(t, topicID)

// Create payer with 1 Hbar
payerId, payerPrivateKey, err := createAccount(&env)
require.NoError(t, err)

customFeeLimit := NewCustomFeeLimit().
SetPayerId(payerId).
AddCustomFee(NewCustomFixedFee().SetAmount(hbar))

// Submit a message to the revenue generating topic with custom fee limit
env.Client.SetOperator(payerId, payerPrivateKey)
schedule, err := NewTopicMessageSubmitTransaction().
SetMessage("message").
SetTopicID(topicID).
AddCustomFeeLimit(customFeeLimit).
Schedule()
require.NoError(t, err)

resp, err = schedule.Execute(env.Client)
require.NoError(t, err)

receipt, err = resp.SetValidateStatus(true).GetReceipt(env.Client)
require.NoError(t, err)

scheduleID := receipt.ScheduleID

scheduleInfo, err := NewScheduleInfoQuery().
SetScheduleID(*scheduleID).
Execute(env.Client)
require.NoError(t, err)

transactionInterface, err := scheduleInfo.GetScheduledTransaction()
require.NoError(t, err)

topicMessageSubmitTransaction, ok := transactionInterface.(TopicMessageSubmitTransaction)
require.True(t, ok)

require.Equal(t, 1, len(topicMessageSubmitTransaction.GetCustomFeeLimits()))
require.Equal(t, customFeeLimit.String(), topicMessageSubmitTransaction.GetCustomFeeLimits()[0].String())
}
12 changes: 10 additions & 2 deletions sdk/topic_message_submit_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,21 @@ func (tx TopicMessageSubmitTransaction) build() *services.TransactionBody {
}

func (tx TopicMessageSubmitTransaction) buildScheduled() (*services.SchedulableTransactionBody, error) {
return &services.SchedulableTransactionBody{
scheduledBody := &services.SchedulableTransactionBody{
TransactionFee: tx.transactionFee,
Memo: tx.Transaction.memo,
Data: &services.SchedulableTransactionBody_ConsensusSubmitMessage{
ConsensusSubmitMessage: tx.buildProtoBody(),
},
}, nil
}

if tx.customFeeLimits != nil {
for _, customFeeLimit := range tx.customFeeLimits {
scheduledBody.MaxCustomFees = append(scheduledBody.MaxCustomFees, customFeeLimit.toProtobuf())
}
}

return scheduledBody, nil
}

func (tx TopicMessageSubmitTransaction) buildProtoBody() *services.ConsensusSubmitMessageTransactionBody {
Expand Down
36 changes: 36 additions & 0 deletions sdk/topic_message_submit_transaction_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,42 @@ func TestUnitTopicMessageSubmitTransactionClearCustomFeeLimit(t *testing.T) {
require.Equal(t, 0, len(transaction.GetCustomFeeLimits()))
}

func TestUnitTopicMessageSubmitTransactionScheduleCustomFees(t *testing.T) {
t.Parallel()

customFeeLimit1 := NewCustomFeeLimit().
SetPayerId(AccountID{Account: 10}).
AddCustomFee(NewCustomFixedFee().SetAmount(1).
SetDenominatingTokenID(TokenID{Token: 10}))

customFeeLimit2 := NewCustomFeeLimit().
SetPayerId(AccountID{Account: 11}).
AddCustomFee(NewCustomFixedFee().SetAmount(2).
SetDenominatingTokenID(TokenID{Token: 11}))

schedule, err := NewTopicMessageSubmitTransaction().
SetCustomFeeLimits([]*CustomFeeLimit{customFeeLimit1, customFeeLimit2}).
Schedule()
require.NoError(t, err)

require.Equal(t, 2, len(schedule.schedulableBody.MaxCustomFees))
require.Equal(t, int64(customFeeLimit1.PayerId.Account), schedule.schedulableBody.MaxCustomFees[0].AccountId.GetAccountNum())
require.Equal(t, int64(customFeeLimit2.PayerId.Account), schedule.schedulableBody.MaxCustomFees[1].AccountId.GetAccountNum())

txBytes, err := schedule.ToBytes()
require.NoError(t, err)

txFromBytes, err := TransactionFromBytes(txBytes)
require.NoError(t, err)

scheduleFromBytes, ok := txFromBytes.(ScheduleCreateTransaction)
require.True(t, ok)

require.Equal(t, 2, len(scheduleFromBytes.schedulableBody.MaxCustomFees))
require.Equal(t, int64(customFeeLimit1.PayerId.Account), scheduleFromBytes.schedulableBody.MaxCustomFees[0].AccountId.GetAccountNum())
require.Equal(t, int64(customFeeLimit2.PayerId.Account), scheduleFromBytes.schedulableBody.MaxCustomFees[1].AccountId.GetAccountNum())
}

func TestUnitTopicMessageSubmitTransactionSetChunkSize(t *testing.T) {
t.Parallel()

Expand Down
Loading
Loading