github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/token_airdrop_transaction_e2e_test.go (about)

     1  //go:build all || e2e
     2  // +build all e2e
     3  
     4  package hedera
     5  
     6  /*-
     7   *
     8   * Hedera Go SDK
     9   *
    10   * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
    11   *
    12   * Licensed under the Apache License, Version 2.0 (the "License");
    13   * you may not use this file except in compliance with the License.
    14   * You may obtain a copy of the License at
    15   *
    16   *      http://www.apache.org/licenses/LICENSE-2.0
    17   *
    18   * Unless required by applicable law or agreed to in writing, software
    19   * distributed under the License is distributed on an "AS IS" BASIS,
    20   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    21   * See the License for the specific language governing permissions and
    22   * limitations under the License.
    23   *
    24   */
    25  
    26  import (
    27  	"testing"
    28  
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  func TestIntegrationTokenAirdropTransactionTransfersTokensWhenAssociated(t *testing.T) {
    34  	env := NewIntegrationTestEnv(t)
    35  	defer CloseIntegrationTestEnv(env, nil)
    36  
    37  	// Create ft and nft
    38  	tokenID, err := createFungibleToken(&env)
    39  	require.NoError(t, err)
    40  	nftID, err := createNft(&env)
    41  	require.NoError(t, err)
    42  
    43  	// Mint some NFTs
    44  	txResponse, err := NewTokenMintTransaction().
    45  		SetTokenID(nftID).
    46  		SetMetadatas(mintMetadata).
    47  		Execute(env.Client)
    48  	require.NoError(t, err)
    49  
    50  	receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client)
    51  	require.NoError(t, err)
    52  
    53  	nftSerials := receipt.SerialNumbers
    54  
    55  	// Create receiver with unlimited auto associations and receiverSig = false
    56  	receiver, _, err := createAccount(&env, func(tx *AccountCreateTransaction) {
    57  		tx.SetMaxAutomaticTokenAssociations(-1)
    58  	})
    59  	require.NoError(t, err)
    60  
    61  	// Airdrop the tokens
    62  	airdropTx, err := NewTokenAirdropTransaction().
    63  		AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, receiver).
    64  		AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, receiver).
    65  		AddTokenTransfer(tokenID, receiver, 100).
    66  		AddTokenTransfer(tokenID, env.OperatorID, -100).
    67  		Execute(env.Client)
    68  	require.NoError(t, err)
    69  
    70  	_, err = airdropTx.SetValidateStatus(true).GetReceipt(env.Client)
    71  	require.NoError(t, err)
    72  
    73  	// Verify the receiver holds the tokens via query
    74  	receiverAccountBalance, err := NewAccountBalanceQuery().
    75  		SetAccountID(receiver).
    76  		Execute(env.Client)
    77  	require.NoError(t, err)
    78  	assert.Equal(t, uint64(100), receiverAccountBalance.Tokens.Get(tokenID))
    79  	assert.Equal(t, uint64(2), receiverAccountBalance.Tokens.Get(nftID))
    80  
    81  	// Verify the operator does not hold the tokens
    82  	operatorBalance, err := NewAccountBalanceQuery().
    83  		SetAccountID(env.OperatorID).
    84  		Execute(env.Client)
    85  	require.NoError(t, err)
    86  	assert.Equal(t, uint64(1_000_000-100), operatorBalance.Tokens.Get(tokenID))
    87  	assert.Equal(t, uint64(8), operatorBalance.Tokens.Get(nftID))
    88  }
    89  func TestIntegrationTokenAirdropTransactionPendingTokensWhenNotAssociated(t *testing.T) {
    90  	env := NewIntegrationTestEnv(t)
    91  	defer CloseIntegrationTestEnv(env, nil)
    92  
    93  	// Create ft and nft
    94  	tokenID, err := createFungibleToken(&env)
    95  	require.NoError(t, err)
    96  	nftID, err := createNft(&env)
    97  	require.NoError(t, err)
    98  
    99  	// Mint some NFTs
   100  	txResponse, err := NewTokenMintTransaction().
   101  		SetTokenID(nftID).
   102  		SetMetadatas(mintMetadata).
   103  		Execute(env.Client)
   104  	require.NoError(t, err)
   105  
   106  	receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   107  	require.NoError(t, err)
   108  
   109  	nftSerials := receipt.SerialNumbers
   110  
   111  	// Create receiver
   112  	receiver, _, err := createAccount(&env)
   113  	require.NoError(t, err)
   114  
   115  	// Airdrop the tokens
   116  	airdropTx, err := NewTokenAirdropTransaction().
   117  		AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, receiver).
   118  		AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, receiver).
   119  		AddTokenTransfer(tokenID, receiver, 100).
   120  		AddTokenTransfer(tokenID, env.OperatorID, -100).
   121  		Execute(env.Client)
   122  	require.NoError(t, err)
   123  
   124  	record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client)
   125  	require.NoError(t, err)
   126  
   127  	// verify the pending airdrop record
   128  	assert.Equal(t, 3, len(record.PendingAirdropRecords))
   129  	assert.Equal(t, uint64(100), record.PendingAirdropRecords[0].pendingAirdropAmount)
   130  	assert.Nil(t, record.PendingAirdropRecords[0].pendingAirdropId.nftID)
   131  	assert.Equal(t, tokenID, *record.PendingAirdropRecords[0].pendingAirdropId.tokenID)
   132  
   133  	assert.Equal(t, uint64(0), record.PendingAirdropRecords[1].pendingAirdropAmount)
   134  	assert.Nil(t, record.PendingAirdropRecords[1].pendingAirdropId.tokenID)
   135  	assert.Equal(t, nftID.Nft(nftSerials[0]), *record.PendingAirdropRecords[1].pendingAirdropId.nftID)
   136  
   137  	assert.Equal(t, uint64(0), record.PendingAirdropRecords[2].pendingAirdropAmount)
   138  	assert.Nil(t, record.PendingAirdropRecords[2].pendingAirdropId.tokenID)
   139  	assert.Equal(t, nftID.Nft(nftSerials[1]), *record.PendingAirdropRecords[2].pendingAirdropId.nftID)
   140  
   141  	// Verify the receiver does not hold the tokens via query
   142  	receiverAccountBalance, err := NewAccountBalanceQuery().
   143  		SetAccountID(receiver).
   144  		Execute(env.Client)
   145  	require.NoError(t, err)
   146  	assert.Equal(t, uint64(0), receiverAccountBalance.Tokens.Get(tokenID))
   147  	assert.Equal(t, uint64(0), receiverAccountBalance.Tokens.Get(nftID))
   148  
   149  	// Verify the operator does hold the tokens
   150  	operatorBalance, err := NewAccountBalanceQuery().
   151  		SetAccountID(env.OperatorID).
   152  		Execute(env.Client)
   153  	require.NoError(t, err)
   154  	assert.Equal(t, uint64(1_000_000), operatorBalance.Tokens.Get(tokenID))
   155  	assert.Equal(t, uint64(10), operatorBalance.Tokens.Get(nftID))
   156  }
   157  
   158  func TestIntegrationTokenAirdropTransactionCreatesHollowAccount(t *testing.T) {
   159  	env := NewIntegrationTestEnv(t)
   160  	defer CloseIntegrationTestEnv(env, nil)
   161  
   162  	// Create ft and nft
   163  	tokenID, err := createFungibleToken(&env)
   164  	require.NoError(t, err)
   165  	nftID, err := createNft(&env)
   166  	require.NoError(t, err)
   167  
   168  	// Mint some NFTs
   169  	txResponse, err := NewTokenMintTransaction().
   170  		SetTokenID(nftID).
   171  		SetMetadatas(mintMetadata).
   172  		Execute(env.Client)
   173  	require.NoError(t, err)
   174  
   175  	receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   176  	require.NoError(t, err)
   177  
   178  	nftSerials := receipt.SerialNumbers
   179  
   180  	// Create a ECDSA private key
   181  	privateKey, err := PrivateKeyGenerateEcdsa()
   182  	if err != nil {
   183  		println(err.Error())
   184  	}
   185  	// Extract the ECDSA public key public key
   186  	publicKey := privateKey.PublicKey()
   187  
   188  	aliasAccountId := publicKey.ToAccountID(0, 0)
   189  
   190  	// should lazy-create and transfer the tokens
   191  	airdropTx, err := NewTokenAirdropTransaction().
   192  		AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, *aliasAccountId).
   193  		AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, *aliasAccountId).
   194  		AddTokenTransfer(tokenID, *aliasAccountId, 100).
   195  		AddTokenTransfer(tokenID, env.OperatorID, -100).
   196  		Execute(env.Client)
   197  	require.NoError(t, err)
   198  
   199  	_, err = airdropTx.SetValidateStatus(true).GetRecord(env.Client)
   200  	require.NoError(t, err)
   201  
   202  	// Verify the receiver holds the tokens via query
   203  	receiverAccountBalance, err := NewAccountBalanceQuery().
   204  		SetAccountID(*aliasAccountId).
   205  		Execute(env.Client)
   206  	require.NoError(t, err)
   207  	assert.Equal(t, uint64(100), receiverAccountBalance.Tokens.Get(tokenID))
   208  	assert.Equal(t, uint64(2), receiverAccountBalance.Tokens.Get(nftID))
   209  
   210  	// Verify the operator does not hold the tokens
   211  	operatorBalance, err := NewAccountBalanceQuery().
   212  		SetAccountID(env.OperatorID).
   213  		Execute(env.Client)
   214  	require.NoError(t, err)
   215  	assert.Equal(t, uint64(1_000_000-100), operatorBalance.Tokens.Get(tokenID))
   216  	assert.Equal(t, uint64(8), operatorBalance.Tokens.Get(nftID))
   217  }
   218  
   219  func TestIntegrationTokenAirdropTransactionWithCustomFees(t *testing.T) {
   220  	env := NewIntegrationTestEnv(t)
   221  	defer CloseIntegrationTestEnv(env, nil)
   222  
   223  	// Create receiver with unlimited auto associations and receiverSig = false
   224  	receiver, _, err := createAccount(&env, func(tx *AccountCreateTransaction) {
   225  		tx.SetMaxAutomaticTokenAssociations(-1)
   226  	})
   227  	require.NoError(t, err)
   228  
   229  	// create fungible token with custom fee another token
   230  	customFeeTokenID, err := createFungibleToken(&env)
   231  	require.NoError(t, err)
   232  
   233  	// make the custom fee to be paid by the sender and the fee collector to be the operator account
   234  	fee := NewCustomFixedFee().
   235  		SetFeeCollectorAccountID(env.OperatorID).
   236  		SetDenominatingTokenID(customFeeTokenID).
   237  		SetAmount(1).
   238  		SetAllCollectorsAreExempt(true)
   239  
   240  	txResponse, err := NewTokenCreateTransaction().
   241  		SetTokenName("Test Fungible Token").
   242  		SetTokenSymbol("TFT").
   243  		SetTokenMemo("I was created for integration tests").
   244  		SetDecimals(3).
   245  		SetInitialSupply(1_000_000).
   246  		SetMaxSupply(1_000_000).
   247  		SetTreasuryAccountID(env.OperatorID).
   248  		SetSupplyType(TokenSupplyTypeFinite).
   249  		SetAdminKey(env.OperatorKey).
   250  		SetFreezeKey(env.OperatorKey).
   251  		SetSupplyKey(env.OperatorKey).
   252  		SetMetadataKey(env.OperatorKey).
   253  		SetPauseKey(env.OperatorKey).
   254  		SetCustomFees([]Fee{fee}).
   255  		Execute(env.Client)
   256  
   257  	require.NoError(t, err)
   258  
   259  	receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   260  	tokenID := receipt.TokenID
   261  
   262  	// create sender account with unlimited associations and send some tokens to it
   263  	sender, senderKey, err := createAccount(&env, func(tx *AccountCreateTransaction) {
   264  		tx.SetMaxAutomaticTokenAssociations(-1)
   265  	})
   266  	require.NoError(t, err)
   267  
   268  	// associate the token to the sender
   269  	frozenTxn, err := NewTokenAssociateTransaction().
   270  		SetAccountID(sender).
   271  		AddTokenID(*tokenID).
   272  		FreezeWith(env.Client)
   273  	require.NoError(t, err)
   274  	txResponse, err = frozenTxn.Sign(senderKey).Execute(env.Client)
   275  	require.NoError(t, err)
   276  	_, err = txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   277  	require.NoError(t, err)
   278  
   279  	// send tokens to the sender
   280  	txResponse, err = NewTransferTransaction().
   281  		AddTokenTransfer(customFeeTokenID, sender, 100).
   282  		AddTokenTransfer(customFeeTokenID, env.OperatorID, -100).
   283  		AddTokenTransfer(*tokenID, sender, 100).
   284  		AddTokenTransfer(*tokenID, env.OperatorID, -100).
   285  		Execute(env.Client)
   286  	require.NoError(t, err)
   287  	_, err = txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   288  	require.NoError(t, err)
   289  
   290  	// airdrop the tokens from the sender to the receiver
   291  	frozenTx, err := NewTokenAirdropTransaction().
   292  		AddTokenTransfer(*tokenID, receiver, 100).
   293  		AddTokenTransfer(*tokenID, sender, -100).
   294  		FreezeWith(env.Client)
   295  	require.NoError(t, err)
   296  	airdropTx, err := frozenTx.
   297  		Sign(senderKey).
   298  		Execute(env.Client)
   299  	require.NoError(t, err)
   300  	_, err = airdropTx.SetValidateStatus(true).GetRecord(env.Client)
   301  	require.NoError(t, err)
   302  
   303  	// verify the custom fee has been paid by the sender to the collector
   304  	receiverAccountBalance, err := NewAccountBalanceQuery().
   305  		SetAccountID(receiver).
   306  		Execute(env.Client)
   307  	require.NoError(t, err)
   308  	assert.Equal(t, uint64(100), receiverAccountBalance.Tokens.Get(*tokenID))
   309  
   310  	senderAccountBalance, err := NewAccountBalanceQuery().
   311  		SetAccountID(sender).
   312  		Execute(env.Client)
   313  	require.NoError(t, err)
   314  	assert.Equal(t, uint64(0), senderAccountBalance.Tokens.Get(*tokenID))
   315  	assert.Equal(t, uint64(99), senderAccountBalance.Tokens.Get(customFeeTokenID))
   316  
   317  	operatorBalance, err := NewAccountBalanceQuery().
   318  		SetAccountID(env.OperatorID).
   319  		Execute(env.Client)
   320  	require.NoError(t, err)
   321  	assert.Equal(t, uint64(1_000_000-100), operatorBalance.Tokens.Get(*tokenID))
   322  	assert.Equal(t, uint64(1_000_000-100+1), operatorBalance.Tokens.Get(customFeeTokenID))
   323  }
   324  func TestIntegrationTokenAirdropTransactionWithReceiverSigTrue(t *testing.T) {
   325  	env := NewIntegrationTestEnv(t)
   326  	defer CloseIntegrationTestEnv(env, nil)
   327  
   328  	// create fungible token
   329  	tokenID, err := createFungibleToken(&env)
   330  	require.NoError(t, err)
   331  
   332  	// create nft
   333  	nftID, err := createNft(&env)
   334  	require.NoError(t, err)
   335  
   336  	// Mint some NFTs
   337  	txResponse, err := NewTokenMintTransaction().
   338  		SetTokenID(nftID).
   339  		SetMetadatas(mintMetadata).
   340  		Execute(env.Client)
   341  	require.NoError(t, err)
   342  
   343  	receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   344  	require.NoError(t, err)
   345  
   346  	nftSerials := receipt.SerialNumbers
   347  
   348  	// create receiver with unlimited auto associations and receiverSig = true
   349  	newKey, err := PrivateKeyGenerateEd25519()
   350  	require.NoError(t, err)
   351  
   352  	accountCreateFrozen, err := NewAccountCreateTransaction().
   353  		SetKey(newKey).
   354  		SetInitialBalance(NewHbar(3)).
   355  		SetReceiverSignatureRequired(true).
   356  		SetMaxAutomaticTokenAssociations(-1).
   357  		FreezeWith(env.Client)
   358  	require.NoError(t, err)
   359  	accountCreate, err := accountCreateFrozen.Sign(newKey).Execute(env.Client)
   360  	require.NoError(t, err)
   361  	receipt, err = accountCreate.SetValidateStatus(true).GetReceipt(env.Client)
   362  	require.NoError(t, err)
   363  	receiver := *receipt.AccountID
   364  
   365  	// airdrop the tokens
   366  	airdropTx, err := NewTokenAirdropTransaction().
   367  		AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, receiver).
   368  		AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, receiver).
   369  		AddTokenTransfer(tokenID, receiver, 100).
   370  		AddTokenTransfer(tokenID, env.OperatorID, -100).
   371  		Execute(env.Client)
   372  	require.NoError(t, err)
   373  	_, err = airdropTx.SetValidateStatus(true).GetReceipt(env.Client)
   374  	require.NoError(t, err)
   375  }
   376  
   377  func TestIntegrationTokenAirdropTransactionWithNoBalanceFT(t *testing.T) {
   378  	env := NewIntegrationTestEnv(t)
   379  	defer CloseIntegrationTestEnv(env, nil)
   380  
   381  	// create fungible token
   382  	tokenID, _ := createFungibleToken(&env)
   383  
   384  	// create spender and approve to it some tokens
   385  	spender, spenderKey, err := createAccount(&env, func(tx *AccountCreateTransaction) {
   386  		tx.SetMaxAutomaticTokenAssociations(-1)
   387  	})
   388  	require.NoError(t, err)
   389  
   390  	// create sender
   391  	sender, senderKey, err := createAccount(&env, func(tx *AccountCreateTransaction) {
   392  		tx.SetMaxAutomaticTokenAssociations(-1)
   393  	})
   394  	require.NoError(t, err)
   395  
   396  	// transfer ft to sender
   397  	txResponse, err := NewTransferTransaction().
   398  		AddTokenTransfer(tokenID, sender, 100).
   399  		AddTokenTransfer(tokenID, env.OperatorID, -100).
   400  		Execute(env.Client)
   401  	require.NoError(t, err)
   402  	_, err = txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   403  	require.NoError(t, err)
   404  
   405  	// approve allowance to the spender
   406  	frozenTx, err := NewAccountAllowanceApproveTransaction().
   407  		ApproveTokenAllowance(tokenID, sender, spender, 100).
   408  		FreezeWith(env.Client)
   409  	require.NoError(t, err)
   410  	txResponse, err = frozenTx.Sign(senderKey).Execute(env.Client)
   411  	require.NoError(t, err)
   412  	_, err = txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   413  	require.NoError(t, err)
   414  
   415  	// airdrop the tokens from the sender to the spender via approval
   416  	frozenTxn, err := NewTokenAirdropTransaction().
   417  		AddTokenTransfer(tokenID, spender, 100).
   418  		AddApprovedTokenTransfer(tokenID, sender, -100, true).
   419  		SetTransactionID(TransactionIDGenerate(spender)).
   420  		FreezeWith(env.Client)
   421  	require.NoError(t, err)
   422  	_, err = frozenTxn.
   423  		Sign(spenderKey).
   424  		Execute(env.Client)
   425  	assert.ErrorContains(t, err, "NOT_SUPPORTED")
   426  }
   427  
   428  func TestIntegrationTokenAirdropTransactionWithNoBalanceNFT(t *testing.T) {
   429  	env := NewIntegrationTestEnv(t)
   430  	defer CloseIntegrationTestEnv(env, nil)
   431  
   432  	// create nft
   433  	nftID, err := createNft(&env)
   434  	require.NoError(t, err)
   435  
   436  	// Mint some NFTs
   437  	txResponse, err := NewTokenMintTransaction().
   438  		SetTokenID(nftID).
   439  		SetMetadatas(mintMetadata).
   440  		Execute(env.Client)
   441  	require.NoError(t, err)
   442  
   443  	receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   444  	require.NoError(t, err)
   445  
   446  	nftSerials := receipt.SerialNumbers
   447  
   448  	// create spender and approve to it some tokens
   449  	spender, spenderKey, err := createAccount(&env, func(tx *AccountCreateTransaction) {
   450  		tx.SetMaxAutomaticTokenAssociations(-1)
   451  	})
   452  	require.NoError(t, err)
   453  
   454  	// create sender
   455  	sender, senderKey, err := createAccount(&env, func(tx *AccountCreateTransaction) {
   456  		tx.SetMaxAutomaticTokenAssociations(-1)
   457  	})
   458  	require.NoError(t, err)
   459  
   460  	// transfer ft to sender
   461  	txResponse, err = NewTransferTransaction().
   462  		AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, sender).
   463  		AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, sender).
   464  		Execute(env.Client)
   465  	require.NoError(t, err)
   466  	_, err = txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   467  	require.NoError(t, err)
   468  
   469  	// approve allowance to the spender
   470  	frozenTx, err := NewAccountAllowanceApproveTransaction().
   471  		ApproveTokenNftAllowance(nftID.Nft(nftSerials[0]), sender, spender).
   472  		ApproveTokenNftAllowance(nftID.Nft(nftSerials[1]), sender, spender).
   473  		FreezeWith(env.Client)
   474  	require.NoError(t, err)
   475  	txResponse, err = frozenTx.Sign(senderKey).Execute(env.Client)
   476  	require.NoError(t, err)
   477  	_, err = txResponse.SetValidateStatus(true).GetReceipt(env.Client)
   478  	require.NoError(t, err)
   479  
   480  	// airdrop the tokens from the sender to the spender via approval
   481  	frozenTxn, err := NewTokenAirdropTransaction().
   482  		AddApprovedNftTransfer(nftID.Nft(nftSerials[0]), sender, spender, true).
   483  		AddApprovedNftTransfer(nftID.Nft(nftSerials[1]), sender, spender, true).
   484  		SetTransactionID(TransactionIDGenerate(spender)).
   485  		FreezeWith(env.Client)
   486  	require.NoError(t, err)
   487  	_, err = frozenTxn.
   488  		Sign(spenderKey).
   489  		Execute(env.Client)
   490  	assert.ErrorContains(t, err, "NOT_SUPPORTED")
   491  }
   492  
   493  func TestIntegrationTokenAirdropTransactionWithInvalidBody(t *testing.T) {
   494  	env := NewIntegrationTestEnv(t)
   495  	defer CloseIntegrationTestEnv(env, nil)
   496  
   497  	// create fungible token
   498  	tokenID, _ := createFungibleToken(&env)
   499  
   500  	// create receiver
   501  	receiver, _, err := createAccount(&env, func(tx *AccountCreateTransaction) {
   502  		tx.SetMaxAutomaticTokenAssociations(-1)
   503  	})
   504  	require.NoError(t, err)
   505  
   506  	_, err = NewTokenAirdropTransaction().
   507  		Execute(env.Client)
   508  	require.ErrorContains(t, err, "EMPTY_TOKEN_TRANSFER_BODY")
   509  
   510  	_, err = NewTokenAirdropTransaction().
   511  		AddTokenTransfer(tokenID, receiver, 100).
   512  		AddTokenTransfer(tokenID, receiver, 100).
   513  		Execute(env.Client)
   514  	require.ErrorContains(t, err, "INVALID_TRANSACTION_BODY")
   515  }