github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/transfer_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 // TransferTransaction 32 // Transfers cryptocurrency among two or more accounts by making the desired adjustments to their 33 // balances. Each transfer list can specify up to 10 adjustments. Each negative amount is withdrawn 34 // from the corresponding account (a sender), and each positive one is added to the corresponding 35 // account (a receiver). The amounts list must sum to zero. Each amount is a number of tinybars 36 // (there are 100,000,000 tinybars in one hbar). If any sender account fails to have sufficient 37 // hbars, then the entire transaction fails, and none of those transfers occur, though the 38 // transaction fee is still charged. This transaction must be signed by the keys for all the sending 39 // accounts, and for any receiving accounts that have receiverSigRequired == true. The signatures 40 // are in the same order as the accounts, skipping those accounts that don't need a signature. 41 type TransferTransaction struct { 42 Transaction 43 tokenTransfers map[TokenID]*_TokenTransfer 44 hbarTransfers []*_HbarTransfer 45 nftTransfers map[TokenID][]*_TokenNftTransfer 46 } 47 48 // NewTransferTransaction creates TransferTransaction which 49 // transfers cryptocurrency among two or more accounts by making the desired adjustments to their 50 // balances. Each transfer list can specify up to 10 adjustments. Each negative amount is withdrawn 51 // from the corresponding account (a sender), and each positive one is added to the corresponding 52 // account (a receiver). The amounts list must sum to zero. Each amount is a number of tinybars 53 // (there are 100,000,000 tinybars in one hbar). If any sender account fails to have sufficient 54 // hbars, then the entire transaction fails, and none of those transfers occur, though the 55 // transaction fee is still charged. This transaction must be signed by the keys for all the sending 56 // accounts, and for any receiving accounts that have receiverSigRequired == true. The signatures 57 // are in the same order as the accounts, skipping those accounts that don't need a signature. 58 func NewTransferTransaction() *TransferTransaction { 59 tx := TransferTransaction{ 60 Transaction: _NewTransaction(), 61 tokenTransfers: make(map[TokenID]*_TokenTransfer), 62 hbarTransfers: make([]*_HbarTransfer, 0), 63 nftTransfers: make(map[TokenID][]*_TokenNftTransfer), 64 } 65 66 tx._SetDefaultMaxTransactionFee(NewHbar(1)) 67 68 return &tx 69 } 70 71 func _TransferTransactionFromProtobuf(tx Transaction, pb *services.TransactionBody) *TransferTransaction { 72 tokenTransfers := make(map[TokenID]*_TokenTransfer) 73 nftTransfers := make(map[TokenID][]*_TokenNftTransfer) 74 75 for _, tokenTransfersList := range pb.GetCryptoTransfer().GetTokenTransfers() { 76 tok := _TokenIDFromProtobuf(tokenTransfersList.Token) 77 tokenTransfers[*tok] = _TokenTransferPrivateFromProtobuf(tokenTransfersList) 78 } 79 80 for _, tokenTransfersList := range pb.GetCryptoTransfer().GetTokenTransfers() { 81 if tokenID := _TokenIDFromProtobuf(tokenTransfersList.Token); tokenID != nil { 82 for _, aa := range tokenTransfersList.GetNftTransfers() { 83 if nftTransfers[*tokenID] == nil { 84 nftTransfers[*tokenID] = make([]*_TokenNftTransfer, 0) 85 } 86 nftTransfer := _NftTransferFromProtobuf(aa) 87 nftTransfers[*tokenID] = append(nftTransfers[*tokenID], &nftTransfer) 88 } 89 } 90 } 91 92 return &TransferTransaction{ 93 Transaction: tx, 94 hbarTransfers: _HbarTransferFromProtobuf(pb.GetCryptoTransfer().GetTransfers().GetAccountAmounts()), 95 tokenTransfers: tokenTransfers, 96 nftTransfers: nftTransfers, 97 } 98 } 99 100 // SetTokenTransferApproval Sets the desired token unit balance adjustments 101 func (tx *TransferTransaction) SetTokenTransferApproval(tokenID TokenID, accountID AccountID, approval bool) *TransferTransaction { //nolint 102 for token, tokenTransfer := range tx.tokenTransfers { 103 if token.Compare(tokenID) == 0 { 104 for _, transfer := range tokenTransfer.Transfers { 105 if transfer.accountID.Compare(accountID) == 0 { 106 transfer.IsApproved = approval 107 } 108 } 109 } 110 } 111 112 return tx 113 } 114 115 // SetHbarTransferApproval Sets the desired hbar balance adjustments 116 func (tx *TransferTransaction) SetHbarTransferApproval(spenderAccountID AccountID, approval bool) *TransferTransaction { //nolint 117 for _, k := range tx.hbarTransfers { 118 if k.accountID.String() == spenderAccountID.String() { 119 k.IsApproved = approval 120 } 121 } 122 return tx 123 } 124 125 // SetNftTransferApproval Sets the desired nft token unit balance adjustments 126 func (tx *TransferTransaction) SetNftTransferApproval(nftID NftID, approval bool) *TransferTransaction { 127 for token, nftTransfers := range tx.nftTransfers { 128 if token.Compare(nftID.TokenID) == 0 { 129 for _, nftTransfer := range nftTransfers { 130 if nftTransfer.SerialNumber == nftID.SerialNumber { 131 nftTransfer.IsApproved = approval 132 } 133 } 134 } 135 } 136 return tx 137 } 138 139 // GetNftTransfers returns the nft transfers 140 func (tx *TransferTransaction) GetNftTransfers() map[TokenID][]_TokenNftTransfer { 141 nftResult := make(map[TokenID][]_TokenNftTransfer) 142 for token, nftTransfers := range tx.nftTransfers { 143 tempArray := make([]_TokenNftTransfer, 0) 144 for _, nftTransfer := range nftTransfers { 145 tempArray = append(tempArray, *nftTransfer) 146 } 147 148 nftResult[token] = tempArray 149 } 150 151 return nftResult 152 } 153 154 // GetTokenTransfers returns the token transfers 155 func (tx *TransferTransaction) GetTokenTransfers() map[TokenID][]TokenTransfer { 156 transfers := make(map[TokenID][]TokenTransfer) 157 for tokenID, tokenTransfers := range tx.tokenTransfers { 158 tokenTransfersList := make([]TokenTransfer, 0) 159 160 for _, transfer := range tokenTransfers.Transfers { 161 var acc AccountID 162 if transfer.accountID != nil { 163 acc = *transfer.accountID 164 } 165 tokenTransfersList = append(tokenTransfersList, TokenTransfer{ 166 AccountID: acc, 167 Amount: transfer.Amount.AsTinybar(), 168 IsApproved: transfer.IsApproved, 169 }) 170 } 171 172 tempTokenTransferList := _TokenTransfers{tokenTransfersList} 173 174 transfers[tokenID] = tempTokenTransferList.transfers 175 } 176 177 return transfers 178 } 179 180 // GetHbarTransfers returns the hbar transfers 181 func (tx *TransferTransaction) GetHbarTransfers() map[AccountID]Hbar { 182 result := make(map[AccountID]Hbar) 183 for _, hbarTransfers := range tx.hbarTransfers { 184 result[*hbarTransfers.accountID] = hbarTransfers.Amount 185 } 186 return result 187 } 188 189 // AddHbarTransfer Sets The desired hbar balance adjustments 190 func (tx *TransferTransaction) AddHbarTransfer(accountID AccountID, amount Hbar) *TransferTransaction { 191 tx._RequireNotFrozen() 192 193 for _, transfer := range tx.hbarTransfers { 194 if transfer.accountID.Compare(accountID) == 0 { 195 transfer.Amount = HbarFromTinybar(amount.AsTinybar() + transfer.Amount.AsTinybar()) 196 return tx 197 } 198 } 199 200 tx.hbarTransfers = append(tx.hbarTransfers, &_HbarTransfer{ 201 accountID: &accountID, 202 Amount: amount, 203 IsApproved: false, 204 }) 205 206 return tx 207 } 208 209 // GetTokenIDDecimals returns the token decimals 210 func (tx *TransferTransaction) GetTokenIDDecimals() map[TokenID]uint32 { 211 result := make(map[TokenID]uint32) 212 for token, tokenTransfer := range tx.tokenTransfers { 213 if tokenTransfer.ExpectedDecimals != nil { 214 result[token] = *tokenTransfer.ExpectedDecimals 215 } 216 } 217 return result 218 } 219 220 // AddTokenTransferWithDecimals Sets the desired token unit balance adjustments with decimals 221 func (tx *TransferTransaction) AddTokenTransferWithDecimals(tokenID TokenID, accountID AccountID, value int64, decimal uint32) *TransferTransaction { //nolint 222 tx._RequireNotFrozen() 223 224 for token, tokenTransfer := range tx.tokenTransfers { 225 if token.Compare(tokenID) == 0 { 226 for _, transfer := range tokenTransfer.Transfers { 227 if transfer.accountID.Compare(accountID) == 0 { 228 transfer.Amount = HbarFromTinybar(transfer.Amount.AsTinybar() + value) 229 tokenTransfer.ExpectedDecimals = &decimal 230 231 return tx 232 } 233 } 234 } 235 } 236 237 if v, ok := tx.tokenTransfers[tokenID]; ok { 238 v.Transfers = append(v.Transfers, &_HbarTransfer{ 239 accountID: &accountID, 240 Amount: HbarFromTinybar(value), 241 IsApproved: false, 242 }) 243 v.ExpectedDecimals = &decimal 244 245 return tx 246 } 247 248 tx.tokenTransfers[tokenID] = &_TokenTransfer{ 249 Transfers: []*_HbarTransfer{{ 250 accountID: &accountID, 251 Amount: HbarFromTinybar(value), 252 IsApproved: false, 253 }}, 254 ExpectedDecimals: &decimal, 255 } 256 257 return tx 258 } 259 260 // AddTokenTransfer Sets the desired token unit balance adjustments 261 // Applicable to tokens of type FUNGIBLE_COMMON. 262 func (tx *TransferTransaction) AddTokenTransfer(tokenID TokenID, accountID AccountID, value int64) *TransferTransaction { //nolint 263 tx._RequireNotFrozen() 264 265 for token, tokenTransfer := range tx.tokenTransfers { 266 if token.Compare(tokenID) == 0 { 267 for _, transfer := range tokenTransfer.Transfers { 268 if transfer.accountID.Compare(accountID) == 0 { 269 transfer.Amount = HbarFromTinybar(transfer.Amount.AsTinybar() + value) 270 271 return tx 272 } 273 } 274 } 275 } 276 277 if v, ok := tx.tokenTransfers[tokenID]; ok { 278 v.Transfers = append(v.Transfers, &_HbarTransfer{ 279 accountID: &accountID, 280 Amount: HbarFromTinybar(value), 281 IsApproved: false, 282 }) 283 284 return tx 285 } 286 287 tx.tokenTransfers[tokenID] = &_TokenTransfer{ 288 Transfers: []*_HbarTransfer{{ 289 accountID: &accountID, 290 Amount: HbarFromTinybar(value), 291 IsApproved: false, 292 }}, 293 } 294 295 return tx 296 } 297 298 // AddNftTransfer Sets the desired nft token unit balance adjustments 299 // Applicable to tokens of type NON_FUNGIBLE_UNIQUE. 300 func (tx *TransferTransaction) AddNftTransfer(nftID NftID, sender AccountID, receiver AccountID) *TransferTransaction { 301 tx._RequireNotFrozen() 302 303 if tx.nftTransfers == nil { 304 tx.nftTransfers = make(map[TokenID][]*_TokenNftTransfer) 305 } 306 307 if tx.nftTransfers[nftID.TokenID] == nil { 308 tx.nftTransfers[nftID.TokenID] = make([]*_TokenNftTransfer, 0) 309 } 310 311 tx.nftTransfers[nftID.TokenID] = append(tx.nftTransfers[nftID.TokenID], &_TokenNftTransfer{ 312 SenderAccountID: sender, 313 ReceiverAccountID: receiver, 314 SerialNumber: nftID.SerialNumber, 315 }) 316 317 return tx 318 } 319 320 // AddHbarTransferWithDecimals adds an approved hbar transfer 321 func (tx *TransferTransaction) AddApprovedHbarTransfer(accountID AccountID, amount Hbar, approve bool) *TransferTransaction { 322 tx._RequireNotFrozen() 323 324 for _, transfer := range tx.hbarTransfers { 325 if transfer.accountID.Compare(accountID) == 0 { 326 transfer.Amount = HbarFromTinybar(amount.AsTinybar() + transfer.Amount.AsTinybar()) 327 transfer.IsApproved = approve 328 return tx 329 } 330 } 331 332 tx.hbarTransfers = append(tx.hbarTransfers, &_HbarTransfer{ 333 accountID: &accountID, 334 Amount: amount, 335 IsApproved: approve, 336 }) 337 338 return tx 339 } 340 341 // AddHbarTransfer adds an approved hbar transfer with decimals 342 func (tx *TransferTransaction) AddApprovedTokenTransferWithDecimals(tokenID TokenID, accountID AccountID, value int64, decimal uint32, approve bool) *TransferTransaction { //nolint 343 tx._RequireNotFrozen() 344 345 for token, tokenTransfer := range tx.tokenTransfers { 346 if token.Compare(tokenID) == 0 { 347 for _, transfer := range tokenTransfer.Transfers { 348 if transfer.accountID.Compare(accountID) == 0 { 349 transfer.Amount = HbarFromTinybar(transfer.Amount.AsTinybar() + value) 350 tokenTransfer.ExpectedDecimals = &decimal 351 for _, transfer := range tokenTransfer.Transfers { 352 transfer.IsApproved = approve 353 } 354 355 return tx 356 } 357 } 358 } 359 } 360 361 if v, ok := tx.tokenTransfers[tokenID]; ok { 362 v.Transfers = append(v.Transfers, &_HbarTransfer{ 363 accountID: &accountID, 364 Amount: HbarFromTinybar(value), 365 IsApproved: approve, 366 }) 367 v.ExpectedDecimals = &decimal 368 369 return tx 370 } 371 372 tx.tokenTransfers[tokenID] = &_TokenTransfer{ 373 Transfers: []*_HbarTransfer{{ 374 accountID: &accountID, 375 Amount: HbarFromTinybar(value), 376 IsApproved: approve, 377 }}, 378 ExpectedDecimals: &decimal, 379 } 380 381 return tx 382 } 383 384 // AddHbarTransfer adds an approved hbar transfer 385 func (tx *TransferTransaction) AddApprovedTokenTransfer(tokenID TokenID, accountID AccountID, value int64, approve bool) *TransferTransaction { //nolint 386 tx._RequireNotFrozen() 387 388 for token, tokenTransfer := range tx.tokenTransfers { 389 if token.Compare(tokenID) == 0 { 390 for _, transfer := range tokenTransfer.Transfers { 391 if transfer.accountID.Compare(accountID) == 0 { 392 transfer.Amount = HbarFromTinybar(transfer.Amount.AsTinybar() + value) 393 transfer.IsApproved = approve 394 395 return tx 396 } 397 } 398 } 399 } 400 401 if v, ok := tx.tokenTransfers[tokenID]; ok { 402 v.Transfers = append(v.Transfers, &_HbarTransfer{ 403 accountID: &accountID, 404 Amount: HbarFromTinybar(value), 405 IsApproved: approve, 406 }) 407 408 return tx 409 } 410 411 tx.tokenTransfers[tokenID] = &_TokenTransfer{ 412 Transfers: []*_HbarTransfer{{ 413 accountID: &accountID, 414 Amount: HbarFromTinybar(value), 415 IsApproved: approve, 416 }}, 417 } 418 419 return tx 420 } 421 422 // AddNftTransfer adds an approved nft transfer 423 func (tx *TransferTransaction) AddApprovedNftTransfer(nftID NftID, sender AccountID, receiver AccountID, approve bool) *TransferTransaction { 424 tx._RequireNotFrozen() 425 426 if tx.nftTransfers == nil { 427 tx.nftTransfers = make(map[TokenID][]*_TokenNftTransfer) 428 } 429 430 if tx.nftTransfers[nftID.TokenID] == nil { 431 tx.nftTransfers[nftID.TokenID] = make([]*_TokenNftTransfer, 0) 432 } 433 434 tx.nftTransfers[nftID.TokenID] = append(tx.nftTransfers[nftID.TokenID], &_TokenNftTransfer{ 435 SenderAccountID: sender, 436 ReceiverAccountID: receiver, 437 SerialNumber: nftID.SerialNumber, 438 IsApproved: approve, 439 }) 440 441 return tx 442 } 443 444 // ---- Required Interfaces ---- // 445 446 // Sign uses the provided privateKey to sign the transaction. 447 func (tx *TransferTransaction) Sign(privateKey PrivateKey) *TransferTransaction { 448 tx.Transaction.Sign(privateKey) 449 return tx 450 } 451 452 // SignWithOperator signs the transaction with client's operator privateKey. 453 func (tx *TransferTransaction) SignWithOperator(client *Client) (*TransferTransaction, error) { 454 _, err := tx.Transaction.signWithOperator(client, tx) 455 if err != nil { 456 return nil, err 457 } 458 return tx, nil 459 } 460 461 // SignWith executes the TransactionSigner and adds the resulting signature data to the Transaction's signature map 462 // with the publicKey as the map key. 463 func (tx *TransferTransaction) SignWith( 464 publicKey PublicKey, 465 signer TransactionSigner, 466 ) *TransferTransaction { 467 tx.Transaction.SignWith(publicKey, signer) 468 return tx 469 } 470 471 // AddSignature adds a signature to the transaction. 472 func (tx *TransferTransaction) AddSignature(publicKey PublicKey, signature []byte) *TransferTransaction { 473 tx.Transaction.AddSignature(publicKey, signature) 474 return tx 475 } 476 477 // When execution is attempted, a single attempt will timeout when this deadline is reached. (The SDK may subsequently retry the execution.) 478 func (tx *TransferTransaction) SetGrpcDeadline(deadline *time.Duration) *TransferTransaction { 479 tx.Transaction.SetGrpcDeadline(deadline) 480 return tx 481 } 482 483 func (tx *TransferTransaction) Freeze() (*TransferTransaction, error) { 484 return tx.FreezeWith(nil) 485 } 486 487 func (tx *TransferTransaction) FreezeWith(client *Client) (*TransferTransaction, error) { 488 _, err := tx.Transaction.freezeWith(client, tx) 489 return tx, err 490 } 491 492 // SetMaxTransactionFee sets the max transaction fee for this TransferTransaction. 493 func (tx *TransferTransaction) SetMaxTransactionFee(fee Hbar) *TransferTransaction { 494 tx.Transaction.SetMaxTransactionFee(fee) 495 return tx 496 } 497 498 // SetRegenerateTransactionID sets if transaction IDs should be regenerated when `TRANSACTION_EXPIRED` is received 499 func (tx *TransferTransaction) SetRegenerateTransactionID(regenerateTransactionID bool) *TransferTransaction { 500 tx.Transaction.SetRegenerateTransactionID(regenerateTransactionID) 501 return tx 502 } 503 504 // SetTransactionMemo sets the memo for this TransferTransaction. 505 func (tx *TransferTransaction) SetTransactionMemo(memo string) *TransferTransaction { 506 tx.Transaction.SetTransactionMemo(memo) 507 return tx 508 } 509 510 // SetTransactionValidDuration sets the valid duration for this TransferTransaction. 511 func (tx *TransferTransaction) SetTransactionValidDuration(duration time.Duration) *TransferTransaction { 512 tx.Transaction.SetTransactionValidDuration(duration) 513 return tx 514 } 515 516 // ToBytes serialise the tx to bytes, no matter if it is signed (locked), or not 517 func (tx *TransferTransaction) ToBytes() ([]byte, error) { 518 bytes, err := tx.Transaction.toBytes(tx) 519 if err != nil { 520 return nil, err 521 } 522 return bytes, nil 523 } 524 525 // SetTransactionID sets the TransactionID for this TransferTransaction. 526 func (tx *TransferTransaction) SetTransactionID(transactionID TransactionID) *TransferTransaction { 527 tx.Transaction.SetTransactionID(transactionID) 528 return tx 529 } 530 531 // SetNodeAccountIDs sets the _Node AccountID for this TransferTransaction. 532 func (tx *TransferTransaction) SetNodeAccountIDs(nodeID []AccountID) *TransferTransaction { 533 tx.Transaction.SetNodeAccountIDs(nodeID) 534 return tx 535 } 536 537 // SetMaxRetry sets the max number of errors before execution will fail. 538 func (tx *TransferTransaction) SetMaxRetry(count int) *TransferTransaction { 539 tx.Transaction.SetMaxRetry(count) 540 return tx 541 } 542 543 // SetMaxBackoff The maximum amount of time to wait between retries. 544 // Every retry attempt will increase the wait time exponentially until it reaches this time. 545 func (tx *TransferTransaction) SetMaxBackoff(max time.Duration) *TransferTransaction { 546 tx.Transaction.SetMaxBackoff(max) 547 return tx 548 } 549 550 // SetMinBackoff sets the minimum amount of time to wait between retries. 551 func (tx *TransferTransaction) SetMinBackoff(min time.Duration) *TransferTransaction { 552 tx.Transaction.SetMinBackoff(min) 553 return tx 554 } 555 556 func (tx *TransferTransaction) SetLogLevel(level LogLevel) *TransferTransaction { 557 tx.Transaction.SetLogLevel(level) 558 return tx 559 } 560 561 func (tx *TransferTransaction) Execute(client *Client) (TransactionResponse, error) { 562 return tx.Transaction.execute(client, tx) 563 } 564 565 func (tx *TransferTransaction) Schedule() (*ScheduleCreateTransaction, error) { 566 return tx.Transaction.schedule(tx) 567 } 568 569 // ----------- Overridden functions ---------------- 570 571 func (tx *TransferTransaction) getName() string { 572 return "TransferTransaction" 573 } 574 575 func (tx *TransferTransaction) validateNetworkOnIDs(client *Client) error { 576 if client == nil || !client.autoValidateChecksums { 577 return nil 578 } 579 var err error 580 for token, tokenTransfer := range tx.tokenTransfers { 581 err = token.ValidateChecksum(client) 582 if err != nil { 583 return err 584 } 585 for _, transfer := range tokenTransfer.Transfers { 586 err = transfer.accountID.ValidateChecksum(client) 587 if err != nil { 588 return err 589 } 590 } 591 if err != nil { 592 return err 593 } 594 } 595 for token, nftTransfers := range tx.nftTransfers { 596 err = token.ValidateChecksum(client) 597 if err != nil { 598 return err 599 } 600 for _, nftTransfer := range nftTransfers { 601 err = nftTransfer.SenderAccountID.ValidateChecksum(client) 602 if err != nil { 603 return err 604 } 605 err = nftTransfer.ReceiverAccountID.ValidateChecksum(client) 606 if err != nil { 607 return err 608 } 609 } 610 } 611 for _, hbarTransfer := range tx.hbarTransfers { 612 err = hbarTransfer.accountID.ValidateChecksum(client) 613 if err != nil { 614 return err 615 } 616 } 617 618 return nil 619 } 620 621 func (tx *TransferTransaction) build() *services.TransactionBody { 622 return &services.TransactionBody{ 623 TransactionFee: tx.transactionFee, 624 Memo: tx.Transaction.memo, 625 TransactionValidDuration: _DurationToProtobuf(tx.GetTransactionValidDuration()), 626 TransactionID: tx.transactionID._ToProtobuf(), 627 Data: &services.TransactionBody_CryptoTransfer{ 628 CryptoTransfer: tx.buildProtoBody(), 629 }, 630 } 631 } 632 633 func (tx *TransferTransaction) buildScheduled() (*services.SchedulableTransactionBody, error) { 634 return &services.SchedulableTransactionBody{ 635 TransactionFee: tx.transactionFee, 636 Memo: tx.Transaction.memo, 637 Data: &services.SchedulableTransactionBody_CryptoTransfer{ 638 CryptoTransfer: tx.buildProtoBody(), 639 }, 640 }, nil 641 } 642 643 func (tx *TransferTransaction) buildProtoBody() *services.CryptoTransferTransactionBody { 644 body := &services.CryptoTransferTransactionBody{ 645 Transfers: &services.TransferList{ 646 AccountAmounts: []*services.AccountAmount{}, 647 }, 648 TokenTransfers: []*services.TokenTransferList{}, 649 } 650 651 if len(tx.hbarTransfers) > 0 { 652 body.Transfers.AccountAmounts = make([]*services.AccountAmount, 0) 653 for _, hbarTransfer := range tx.hbarTransfers { 654 body.Transfers.AccountAmounts = append(body.Transfers.AccountAmounts, &services.AccountAmount{ 655 AccountID: hbarTransfer.accountID._ToProtobuf(), 656 Amount: hbarTransfer.Amount.AsTinybar(), 657 IsApproval: hbarTransfer.IsApproved, 658 }) 659 } 660 } 661 662 if len(tx.tokenTransfers) > 0 { 663 if body.TokenTransfers == nil { 664 body.TokenTransfers = make([]*services.TokenTransferList, 0) 665 } 666 667 for tokenID := range tx.tokenTransfers { 668 transfers := tx.tokenTransfers[tokenID]._ToProtobuf() 669 670 bod := &services.TokenTransferList{ 671 Token: tokenID._ToProtobuf(), 672 Transfers: transfers, 673 } 674 675 if tx.tokenTransfers[tokenID].ExpectedDecimals != nil { 676 bod.ExpectedDecimals = &wrapperspb.UInt32Value{Value: *tx.tokenTransfers[tokenID].ExpectedDecimals} 677 } 678 679 body.TokenTransfers = append(body.TokenTransfers, bod) 680 } 681 } 682 683 if len(tx.nftTransfers) > 0 { 684 if body.TokenTransfers == nil { 685 body.TokenTransfers = make([]*services.TokenTransferList, 0) 686 } 687 688 for tokenID, nftTransferList := range tx.nftTransfers { 689 nftTransfers := make([]*services.NftTransfer, 0) 690 691 for _, nftT := range nftTransferList { 692 nftTransfers = append(nftTransfers, nftT._ToProtobuf()) 693 } 694 695 body.TokenTransfers = append(body.TokenTransfers, &services.TokenTransferList{ 696 Token: tokenID._ToProtobuf(), 697 NftTransfers: nftTransfers, 698 }) 699 } 700 } 701 702 return body 703 } 704 705 func (tx *TransferTransaction) getMethod(channel *_Channel) _Method { 706 return _Method{ 707 transaction: channel._GetCrypto().CryptoTransfer, 708 } 709 } 710 711 func (this *TransferTransaction) _ConstructScheduleProtobuf() (*services.SchedulableTransactionBody, error) { 712 return this.buildScheduled() 713 }