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

     1  package hedera
     2  
     3  /*-
     4   *
     5   * Hedera Go SDK
     6   *
     7   * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
     8   *
     9   * Licensed under the Apache License, Version 2.0 (the "License");
    10   * you may not use this file except in compliance with the License.
    11   * You may obtain a copy of the License at
    12   *
    13   *      http://www.apache.org/licenses/LICENSE-2.0
    14   *
    15   * Unless required by applicable law or agreed to in writing, software
    16   * distributed under the License is distributed on an "AS IS" BASIS,
    17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    18   * See the License for the specific language governing permissions and
    19   * limitations under the License.
    20   *
    21   */
    22  
    23  import (
    24  	"time"
    25  
    26  	"google.golang.org/protobuf/types/known/wrapperspb"
    27  
    28  	"github.com/hashgraph/hedera-protobufs-go/services"
    29  )
    30  
    31  type TokenAirdropTransaction struct {
    32  	Transaction
    33  	tokenTransfers map[TokenID]*_TokenTransfer
    34  	nftTransfers   map[TokenID][]*_TokenNftTransfer
    35  }
    36  
    37  func NewTokenAirdropTransaction() *TokenAirdropTransaction {
    38  	tx := TokenAirdropTransaction{
    39  		Transaction:    _NewTransaction(),
    40  		tokenTransfers: make(map[TokenID]*_TokenTransfer),
    41  		nftTransfers:   make(map[TokenID][]*_TokenNftTransfer),
    42  	}
    43  
    44  	tx._SetDefaultMaxTransactionFee(NewHbar(1))
    45  
    46  	return &tx
    47  }
    48  
    49  func _TokenAirdropTransactionFromProtobuf(tx Transaction, pb *services.TransactionBody) *TokenAirdropTransaction {
    50  	tokenTransfers := make(map[TokenID]*_TokenTransfer)
    51  	nftTransfers := make(map[TokenID][]*_TokenNftTransfer)
    52  
    53  	for _, tokenTransfersList := range pb.GetTokenAirdrop().GetTokenTransfers() {
    54  		tok := _TokenIDFromProtobuf(tokenTransfersList.Token)
    55  		tokenTransfers[*tok] = _TokenTransferPrivateFromProtobuf(tokenTransfersList)
    56  	}
    57  
    58  	for _, tokenTransfersList := range pb.GetTokenAirdrop().GetTokenTransfers() {
    59  		if tokenID := _TokenIDFromProtobuf(tokenTransfersList.Token); tokenID != nil {
    60  			for _, aa := range tokenTransfersList.GetNftTransfers() {
    61  				if nftTransfers[*tokenID] == nil {
    62  					nftTransfers[*tokenID] = make([]*_TokenNftTransfer, 0)
    63  				}
    64  				nftTransfer := _NftTransferFromProtobuf(aa)
    65  				nftTransfers[*tokenID] = append(nftTransfers[*tokenID], &nftTransfer)
    66  			}
    67  		}
    68  	}
    69  
    70  	return &TokenAirdropTransaction{
    71  		Transaction:    tx,
    72  		tokenTransfers: tokenTransfers,
    73  		nftTransfers:   nftTransfers,
    74  	}
    75  }
    76  
    77  // SetTokenTransferApproval Sets the desired token unit balance adjustments
    78  func (tx *TokenAirdropTransaction) SetTokenTransferApproval(tokenID TokenID, accountID AccountID, approval bool) *TokenAirdropTransaction { //nolint
    79  	for token, tokenTransfer := range tx.tokenTransfers {
    80  		if token.equals(tokenID) {
    81  			for _, transfer := range tokenTransfer.Transfers {
    82  				if transfer.accountID._Equals(accountID) {
    83  					transfer.IsApproved = approval
    84  				}
    85  			}
    86  		}
    87  	}
    88  
    89  	return tx
    90  }
    91  
    92  // SetNftTransferApproval Sets the desired nft token unit balance adjustments
    93  func (tx *TokenAirdropTransaction) SetNftTransferApproval(nftID NftID, approval bool) *TokenAirdropTransaction {
    94  	for token, nftTransfers := range tx.nftTransfers {
    95  		if token.equals(nftID.TokenID) {
    96  			for _, nftTransfer := range nftTransfers {
    97  				if nftTransfer.SerialNumber == nftID.SerialNumber {
    98  					nftTransfer.IsApproved = approval
    99  				}
   100  			}
   101  		}
   102  	}
   103  	return tx
   104  }
   105  
   106  // GetNftTransfers returns the nft transfers
   107  func (tx *TokenAirdropTransaction) GetNftTransfers() map[TokenID][]_TokenNftTransfer {
   108  	nftResult := make(map[TokenID][]_TokenNftTransfer)
   109  	for token, nftTransfers := range tx.nftTransfers {
   110  		tempArray := make([]_TokenNftTransfer, 0)
   111  		for _, nftTransfer := range nftTransfers {
   112  			tempArray = append(tempArray, *nftTransfer)
   113  		}
   114  
   115  		nftResult[token] = tempArray
   116  	}
   117  
   118  	return nftResult
   119  }
   120  
   121  // GetTokenTransfers returns the token transfers
   122  func (tx *TokenAirdropTransaction) GetTokenTransfers() map[TokenID][]TokenTransfer {
   123  	transfers := make(map[TokenID][]TokenTransfer)
   124  	for tokenID, tokenTransfers := range tx.tokenTransfers {
   125  		tokenTransfersList := make([]TokenTransfer, 0)
   126  
   127  		for _, transfer := range tokenTransfers.Transfers {
   128  			var acc AccountID
   129  			if transfer.accountID != nil {
   130  				acc = *transfer.accountID
   131  			}
   132  			tokenTransfersList = append(tokenTransfersList, TokenTransfer{
   133  				AccountID:  acc,
   134  				Amount:     transfer.Amount.AsTinybar(),
   135  				IsApproved: transfer.IsApproved,
   136  			})
   137  		}
   138  
   139  		tempTokenTransferList := _TokenTransfers{tokenTransfersList}
   140  
   141  		transfers[tokenID] = tempTokenTransferList.transfers
   142  	}
   143  
   144  	return transfers
   145  }
   146  
   147  // GetTokenIDDecimals returns the token decimals
   148  func (tx *TokenAirdropTransaction) GetTokenIDDecimals() map[TokenID]uint32 {
   149  	result := make(map[TokenID]uint32)
   150  	for token, tokenTransfer := range tx.tokenTransfers {
   151  		if tokenTransfer.ExpectedDecimals != nil {
   152  			result[token] = *tokenTransfer.ExpectedDecimals
   153  		}
   154  	}
   155  	return result
   156  }
   157  
   158  // AddTokenTransferWithDecimals Sets the desired token unit balance adjustments with decimals
   159  func (tx *TokenAirdropTransaction) AddTokenTransferWithDecimals(tokenID TokenID, accountID AccountID, value int64, decimal uint32) *TokenAirdropTransaction { //nolint
   160  	tx._RequireNotFrozen()
   161  
   162  	for token, tokenTransfer := range tx.tokenTransfers {
   163  		if token.equals(tokenID) {
   164  			for _, transfer := range tokenTransfer.Transfers {
   165  				if transfer.accountID._Equals(accountID) {
   166  					transfer.Amount = HbarFromTinybar(transfer.Amount.AsTinybar() + value)
   167  					tokenTransfer.ExpectedDecimals = &decimal
   168  
   169  					return tx
   170  				}
   171  			}
   172  		}
   173  	}
   174  
   175  	if v, ok := tx.tokenTransfers[tokenID]; ok {
   176  		v.Transfers = append(v.Transfers, &_HbarTransfer{
   177  			accountID:  &accountID,
   178  			Amount:     HbarFromTinybar(value),
   179  			IsApproved: false,
   180  		})
   181  		v.ExpectedDecimals = &decimal
   182  
   183  		return tx
   184  	}
   185  
   186  	tx.tokenTransfers[tokenID] = &_TokenTransfer{
   187  		Transfers: []*_HbarTransfer{{
   188  			accountID:  &accountID,
   189  			Amount:     HbarFromTinybar(value),
   190  			IsApproved: false,
   191  		}},
   192  		ExpectedDecimals: &decimal,
   193  	}
   194  
   195  	return tx
   196  }
   197  
   198  // AddTokenTransfer Sets the desired token unit balance adjustments
   199  // Applicable to tokens of type FUNGIBLE_COMMON.
   200  func (tx *TokenAirdropTransaction) AddTokenTransfer(tokenID TokenID, accountID AccountID, value int64) *TokenAirdropTransaction { //nolint
   201  	tx._RequireNotFrozen()
   202  
   203  	for token, tokenTransfer := range tx.tokenTransfers {
   204  		if token.equals(tokenID) {
   205  			for _, transfer := range tokenTransfer.Transfers {
   206  				if transfer.accountID._Equals(accountID) {
   207  					transfer.Amount = HbarFromTinybar(transfer.Amount.AsTinybar() + value)
   208  
   209  					return tx
   210  				}
   211  			}
   212  		}
   213  	}
   214  
   215  	if v, ok := tx.tokenTransfers[tokenID]; ok {
   216  		v.Transfers = append(v.Transfers, &_HbarTransfer{
   217  			accountID:  &accountID,
   218  			Amount:     HbarFromTinybar(value),
   219  			IsApproved: false,
   220  		})
   221  
   222  		return tx
   223  	}
   224  
   225  	tx.tokenTransfers[tokenID] = &_TokenTransfer{
   226  		Transfers: []*_HbarTransfer{{
   227  			accountID:  &accountID,
   228  			Amount:     HbarFromTinybar(value),
   229  			IsApproved: false,
   230  		}},
   231  	}
   232  
   233  	return tx
   234  }
   235  
   236  // AddNftTransfer Sets the desired nft token unit balance adjustments
   237  // Applicable to tokens of type NON_FUNGIBLE_UNIQUE.
   238  func (tx *TokenAirdropTransaction) AddNftTransfer(nftID NftID, sender AccountID, receiver AccountID) *TokenAirdropTransaction {
   239  	tx._RequireNotFrozen()
   240  
   241  	if tx.nftTransfers == nil {
   242  		tx.nftTransfers = make(map[TokenID][]*_TokenNftTransfer)
   243  	}
   244  
   245  	if tx.nftTransfers[nftID.TokenID] == nil {
   246  		tx.nftTransfers[nftID.TokenID] = make([]*_TokenNftTransfer, 0)
   247  	}
   248  
   249  	tx.nftTransfers[nftID.TokenID] = append(tx.nftTransfers[nftID.TokenID], &_TokenNftTransfer{
   250  		SenderAccountID:   sender,
   251  		ReceiverAccountID: receiver,
   252  		SerialNumber:      nftID.SerialNumber,
   253  	})
   254  
   255  	return tx
   256  }
   257  
   258  // AddApprovedTokenTransferWithDecimals adds an approved token transfer with decimals
   259  func (tx *TokenAirdropTransaction) AddApprovedTokenTransferWithDecimals(tokenID TokenID, accountID AccountID, value int64, decimal uint32, approve bool) *TokenAirdropTransaction { //nolint
   260  	tx._RequireNotFrozen()
   261  
   262  	for token, tokenTransfer := range tx.tokenTransfers {
   263  		if token.equals(tokenID) {
   264  			for _, transfer := range tokenTransfer.Transfers {
   265  				if transfer.accountID._Equals(accountID) {
   266  					transfer.Amount = HbarFromTinybar(transfer.Amount.AsTinybar() + value)
   267  					tokenTransfer.ExpectedDecimals = &decimal
   268  					for _, transfer := range tokenTransfer.Transfers {
   269  						transfer.IsApproved = approve
   270  					}
   271  
   272  					return tx
   273  				}
   274  			}
   275  		}
   276  	}
   277  
   278  	if v, ok := tx.tokenTransfers[tokenID]; ok {
   279  		v.Transfers = append(v.Transfers, &_HbarTransfer{
   280  			accountID:  &accountID,
   281  			Amount:     HbarFromTinybar(value),
   282  			IsApproved: approve,
   283  		})
   284  		v.ExpectedDecimals = &decimal
   285  
   286  		return tx
   287  	}
   288  
   289  	tx.tokenTransfers[tokenID] = &_TokenTransfer{
   290  		Transfers: []*_HbarTransfer{{
   291  			accountID:  &accountID,
   292  			Amount:     HbarFromTinybar(value),
   293  			IsApproved: approve,
   294  		}},
   295  		ExpectedDecimals: &decimal,
   296  	}
   297  
   298  	return tx
   299  }
   300  
   301  // AddApprovedTokenTransfer adds an approved token transfer
   302  func (tx *TokenAirdropTransaction) AddApprovedTokenTransfer(tokenID TokenID, accountID AccountID, value int64, approve bool) *TokenAirdropTransaction { //nolint
   303  	tx._RequireNotFrozen()
   304  
   305  	for token, tokenTransfer := range tx.tokenTransfers {
   306  		if token.equals(tokenID) {
   307  			for _, transfer := range tokenTransfer.Transfers {
   308  				if transfer.accountID._Equals(accountID) {
   309  					transfer.Amount = HbarFromTinybar(transfer.Amount.AsTinybar() + value)
   310  					transfer.IsApproved = approve
   311  
   312  					return tx
   313  				}
   314  			}
   315  		}
   316  	}
   317  
   318  	if v, ok := tx.tokenTransfers[tokenID]; ok {
   319  		v.Transfers = append(v.Transfers, &_HbarTransfer{
   320  			accountID:  &accountID,
   321  			Amount:     HbarFromTinybar(value),
   322  			IsApproved: approve,
   323  		})
   324  
   325  		return tx
   326  	}
   327  
   328  	tx.tokenTransfers[tokenID] = &_TokenTransfer{
   329  		Transfers: []*_HbarTransfer{{
   330  			accountID:  &accountID,
   331  			Amount:     HbarFromTinybar(value),
   332  			IsApproved: approve,
   333  		}},
   334  	}
   335  
   336  	return tx
   337  }
   338  
   339  // AddApprovedNftTransfer adds an approved nft transfer
   340  func (tx *TokenAirdropTransaction) AddApprovedNftTransfer(nftID NftID, sender AccountID, receiver AccountID, approve bool) *TokenAirdropTransaction {
   341  	tx._RequireNotFrozen()
   342  
   343  	if tx.nftTransfers == nil {
   344  		tx.nftTransfers = make(map[TokenID][]*_TokenNftTransfer)
   345  	}
   346  
   347  	if tx.nftTransfers[nftID.TokenID] == nil {
   348  		tx.nftTransfers[nftID.TokenID] = make([]*_TokenNftTransfer, 0)
   349  	}
   350  
   351  	tx.nftTransfers[nftID.TokenID] = append(tx.nftTransfers[nftID.TokenID], &_TokenNftTransfer{
   352  		SenderAccountID:   sender,
   353  		ReceiverAccountID: receiver,
   354  		SerialNumber:      nftID.SerialNumber,
   355  		IsApproved:        approve,
   356  	})
   357  
   358  	return tx
   359  }
   360  
   361  // ---- Required Interfaces ---- //
   362  
   363  // Sign uses the provided privateKey to sign the transaction.
   364  func (tx *TokenAirdropTransaction) Sign(privateKey PrivateKey) *TokenAirdropTransaction {
   365  	tx.Transaction.Sign(privateKey)
   366  	return tx
   367  }
   368  
   369  // SignWithOperator signs the transaction with client's operator privateKey.
   370  func (tx *TokenAirdropTransaction) SignWithOperator(client *Client) (*TokenAirdropTransaction, error) {
   371  	_, err := tx.Transaction.signWithOperator(client, tx)
   372  	if err != nil {
   373  		return nil, err
   374  	}
   375  	return tx, nil
   376  }
   377  
   378  // SignWith executes the TransactionSigner and adds the resulting signature data to the Transaction's signature map
   379  // with the publicKey as the map key.
   380  func (tx *TokenAirdropTransaction) SignWith(
   381  	publicKey PublicKey,
   382  	signer TransactionSigner,
   383  ) *TokenAirdropTransaction {
   384  	tx.Transaction.SignWith(publicKey, signer)
   385  	return tx
   386  }
   387  
   388  // AddSignature adds a signature to the transaction.
   389  func (tx *TokenAirdropTransaction) AddSignature(publicKey PublicKey, signature []byte) *TokenAirdropTransaction {
   390  	tx.Transaction.AddSignature(publicKey, signature)
   391  	return tx
   392  }
   393  
   394  // When execution is attempted, a single attempt will timeout when this deadline is reached. (The SDK may subsequently retry the execution.)
   395  func (tx *TokenAirdropTransaction) SetGrpcDeadline(deadline *time.Duration) *TokenAirdropTransaction {
   396  	tx.Transaction.SetGrpcDeadline(deadline)
   397  	return tx
   398  }
   399  
   400  func (tx *TokenAirdropTransaction) Freeze() (*TokenAirdropTransaction, error) {
   401  	return tx.FreezeWith(nil)
   402  }
   403  
   404  func (tx *TokenAirdropTransaction) FreezeWith(client *Client) (*TokenAirdropTransaction, error) {
   405  	_, err := tx.Transaction.freezeWith(client, tx)
   406  	return tx, err
   407  }
   408  
   409  // SetMaxTransactionFee sets the max transaction fee for this TokenAirdropTransaction.
   410  func (tx *TokenAirdropTransaction) SetMaxTransactionFee(fee Hbar) *TokenAirdropTransaction {
   411  	tx.Transaction.SetMaxTransactionFee(fee)
   412  	return tx
   413  }
   414  
   415  // SetRegenerateTransactionID sets if transaction IDs should be regenerated when `TRANSACTION_EXPIRED` is received
   416  func (tx *TokenAirdropTransaction) SetRegenerateTransactionID(regenerateTransactionID bool) *TokenAirdropTransaction {
   417  	tx.Transaction.SetRegenerateTransactionID(regenerateTransactionID)
   418  	return tx
   419  }
   420  
   421  // SetTransactionMemo sets the memo for this TokenAirdropTransaction.
   422  func (tx *TokenAirdropTransaction) SetTransactionMemo(memo string) *TokenAirdropTransaction {
   423  	tx.Transaction.SetTransactionMemo(memo)
   424  	return tx
   425  }
   426  
   427  // SetTransactionValidDuration sets the valid duration for this TokenAirdropTransaction.
   428  func (tx *TokenAirdropTransaction) SetTransactionValidDuration(duration time.Duration) *TokenAirdropTransaction {
   429  	tx.Transaction.SetTransactionValidDuration(duration)
   430  	return tx
   431  }
   432  
   433  // ToBytes serialise the tx to bytes, no matter if it is signed (locked), or not
   434  func (tx *TokenAirdropTransaction) ToBytes() ([]byte, error) {
   435  	bytes, err := tx.Transaction.toBytes(tx)
   436  	if err != nil {
   437  		return nil, err
   438  	}
   439  	return bytes, nil
   440  }
   441  
   442  // SetTransactionID sets the TransactionID for this TokenAirdropTransaction.
   443  func (tx *TokenAirdropTransaction) SetTransactionID(transactionID TransactionID) *TokenAirdropTransaction {
   444  	tx.Transaction.SetTransactionID(transactionID)
   445  	return tx
   446  }
   447  
   448  // SetNodeAccountIDs sets the _Node AccountID for this TokenAirdropTransaction.
   449  func (tx *TokenAirdropTransaction) SetNodeAccountIDs(nodeID []AccountID) *TokenAirdropTransaction {
   450  	tx.Transaction.SetNodeAccountIDs(nodeID)
   451  	return tx
   452  }
   453  
   454  // SetMaxRetry sets the max number of errors before execution will fail.
   455  func (tx *TokenAirdropTransaction) SetMaxRetry(count int) *TokenAirdropTransaction {
   456  	tx.Transaction.SetMaxRetry(count)
   457  	return tx
   458  }
   459  
   460  // SetMaxBackoff The maximum amount of time to wait between retries.
   461  // Every retry attempt will increase the wait time exponentially until it reaches this time.
   462  func (tx *TokenAirdropTransaction) SetMaxBackoff(max time.Duration) *TokenAirdropTransaction {
   463  	tx.Transaction.SetMaxBackoff(max)
   464  	return tx
   465  }
   466  
   467  // SetMinBackoff sets the minimum amount of time to wait between retries.
   468  func (tx *TokenAirdropTransaction) SetMinBackoff(min time.Duration) *TokenAirdropTransaction {
   469  	tx.Transaction.SetMinBackoff(min)
   470  	return tx
   471  }
   472  
   473  func (tx *TokenAirdropTransaction) SetLogLevel(level LogLevel) *TokenAirdropTransaction {
   474  	tx.Transaction.SetLogLevel(level)
   475  	return tx
   476  }
   477  
   478  func (tx *TokenAirdropTransaction) Execute(client *Client) (TransactionResponse, error) {
   479  	return tx.Transaction.execute(client, tx)
   480  }
   481  
   482  func (tx *TokenAirdropTransaction) Schedule() (*ScheduleCreateTransaction, error) {
   483  	return tx.Transaction.schedule(tx)
   484  }
   485  
   486  // ----------- Overridden functions ----------------
   487  
   488  func (tx *TokenAirdropTransaction) getName() string {
   489  	return "TokenAirdropTransaction"
   490  }
   491  
   492  func (tx *TokenAirdropTransaction) validateNetworkOnIDs(client *Client) error {
   493  	if client == nil || !client.autoValidateChecksums {
   494  		return nil
   495  	}
   496  	var err error
   497  	for token, tokenTransfer := range tx.tokenTransfers {
   498  		err = token.ValidateChecksum(client)
   499  		if err != nil {
   500  			return err
   501  		}
   502  		for _, transfer := range tokenTransfer.Transfers {
   503  			err = transfer.accountID.ValidateChecksum(client)
   504  			if err != nil {
   505  				return err
   506  			}
   507  		}
   508  		if err != nil {
   509  			return err
   510  		}
   511  	}
   512  	for token, nftTransfers := range tx.nftTransfers {
   513  		err = token.ValidateChecksum(client)
   514  		if err != nil {
   515  			return err
   516  		}
   517  		for _, nftTransfer := range nftTransfers {
   518  			err = nftTransfer.SenderAccountID.ValidateChecksum(client)
   519  			if err != nil {
   520  				return err
   521  			}
   522  			err = nftTransfer.ReceiverAccountID.ValidateChecksum(client)
   523  			if err != nil {
   524  				return err
   525  			}
   526  		}
   527  	}
   528  
   529  	return nil
   530  }
   531  
   532  func (tx *TokenAirdropTransaction) build() *services.TransactionBody {
   533  	return &services.TransactionBody{
   534  		TransactionFee:           tx.transactionFee,
   535  		Memo:                     tx.Transaction.memo,
   536  		TransactionValidDuration: _DurationToProtobuf(tx.GetTransactionValidDuration()),
   537  		TransactionID:            tx.transactionID._ToProtobuf(),
   538  		Data: &services.TransactionBody_TokenAirdrop{
   539  			TokenAirdrop: tx.buildProtoBody(),
   540  		},
   541  	}
   542  }
   543  
   544  func (tx *TokenAirdropTransaction) buildScheduled() (*services.SchedulableTransactionBody, error) {
   545  	return &services.SchedulableTransactionBody{
   546  		TransactionFee: tx.transactionFee,
   547  		Memo:           tx.Transaction.memo,
   548  		Data: &services.SchedulableTransactionBody_TokenAirdrop{
   549  			TokenAirdrop: tx.buildProtoBody(),
   550  		},
   551  	}, nil
   552  }
   553  
   554  func (tx *TokenAirdropTransaction) buildProtoBody() *services.TokenAirdropTransactionBody {
   555  	body := &services.TokenAirdropTransactionBody{
   556  		TokenTransfers: []*services.TokenTransferList{},
   557  	}
   558  
   559  	if len(tx.tokenTransfers) > 0 {
   560  		if body.TokenTransfers == nil {
   561  			body.TokenTransfers = make([]*services.TokenTransferList, 0)
   562  		}
   563  
   564  		for tokenID := range tx.tokenTransfers {
   565  			transfers := tx.tokenTransfers[tokenID]._ToProtobuf()
   566  
   567  			bod := &services.TokenTransferList{
   568  				Token:     tokenID._ToProtobuf(),
   569  				Transfers: transfers,
   570  			}
   571  
   572  			if tx.tokenTransfers[tokenID].ExpectedDecimals != nil {
   573  				bod.ExpectedDecimals = &wrapperspb.UInt32Value{Value: *tx.tokenTransfers[tokenID].ExpectedDecimals}
   574  			}
   575  
   576  			body.TokenTransfers = append(body.TokenTransfers, bod)
   577  		}
   578  	}
   579  
   580  	if len(tx.nftTransfers) > 0 {
   581  		if body.TokenTransfers == nil {
   582  			body.TokenTransfers = make([]*services.TokenTransferList, 0)
   583  		}
   584  
   585  		for tokenID, nftTransferList := range tx.nftTransfers {
   586  			nftTransfers := make([]*services.NftTransfer, 0)
   587  
   588  			for _, nftT := range nftTransferList {
   589  				nftTransfers = append(nftTransfers, nftT._ToProtobuf())
   590  			}
   591  
   592  			body.TokenTransfers = append(body.TokenTransfers, &services.TokenTransferList{
   593  				Token:        tokenID._ToProtobuf(),
   594  				NftTransfers: nftTransfers,
   595  			})
   596  		}
   597  	}
   598  
   599  	return body
   600  }
   601  
   602  func (tx *TokenAirdropTransaction) getMethod(channel *_Channel) _Method {
   603  	return _Method{
   604  		transaction: channel._GetToken().AirdropTokens,
   605  	}
   606  }
   607  
   608  func (tx *TokenAirdropTransaction) _ConstructScheduleProtobuf() (*services.SchedulableTransactionBody, error) {
   609  	return tx.buildScheduled()
   610  }