github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/token_claim_airdrop_transaction_e2e_test.go (about) 1 //go:build all || e2e 2 // +build all e2e 3 4 package hedera 5 6 import ( 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 /*- 14 * 15 * Hedera Go SDK 16 * 17 * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC 18 * 19 * Licensed under the Apache License, Version 2.0 (the "License"); 20 * you may not use this file except in compliance with the License. 21 * You may obtain a copy of the License at 22 * 23 * http://www.apache.org/licenses/LICENSE-2.0 24 * 25 * Unless required by applicable law or agreed to in writing, software 26 * distributed under the License is distributed on an "AS IS" BASIS, 27 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 * See the License for the specific language governing permissions and 29 * limitations under the License. 30 * 31 */ 32 33 const tokenClaimAirdropTransferAmount = 100 34 35 func TestIntegrationTokenClaimAirdropCanExecute(t *testing.T) { 36 env := NewIntegrationTestEnv(t) 37 defer CloseIntegrationTestEnv(env, nil) 38 39 // Create fungible token 40 tokenID, err := createFungibleToken(&env) 41 require.NoError(t, err) 42 43 // Create nft 44 nftID, err := createNft(&env) 45 require.NoError(t, err) 46 47 // Mint some NFTs 48 txResponse, err := NewTokenMintTransaction(). 49 SetTokenID(nftID). 50 SetMetadatas(mintMetadata). 51 Execute(env.Client) 52 require.NoError(t, err) 53 54 receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client) 55 require.NoError(t, err) 56 nftSerials := receipt.SerialNumbers 57 58 // Create receiver with 0 auto associations 59 receiver, receiverKey, err := createAccount(&env) 60 require.NoError(t, err) 61 62 // Airdrop the tokens 63 airdropTx, err := NewTokenAirdropTransaction(). 64 AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, receiver). 65 AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, receiver). 66 AddTokenTransfer(tokenID, receiver, tokenClaimAirdropTransferAmount). 67 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 68 Execute(env.Client) 69 require.NoError(t, err) 70 71 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 72 require.NoError(t, err) 73 74 // Claim the tokens with the receiver 75 claimTx, err := NewTokenClaimAirdropTransaction(). 76 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 77 AddPendingAirdropId(record.PendingAirdropRecords[1].GetPendingAirdropId()). 78 AddPendingAirdropId(record.PendingAirdropRecords[2].GetPendingAirdropId()). 79 FreezeWith(env.Client) 80 require.NoError(t, err) 81 82 claimResp, err := claimTx.Sign(receiverKey).Execute(env.Client) 83 require.NoError(t, err) 84 85 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 86 require.NoError(t, err) 87 88 // Verify the receiver holds the tokens via query 89 reciverBalance, err := NewAccountBalanceQuery(). 90 SetAccountID(receiver). 91 Execute(env.Client) 92 require.NoError(t, err) 93 94 require.Equal(t, uint64(tokenClaimAirdropTransferAmount), reciverBalance.Tokens.Get(tokenID)) 95 require.Equal(t, uint64(2), reciverBalance.Tokens.Get(nftID)) 96 97 // Verify the operator does not hold the tokens 98 operatorBalance, err := NewAccountBalanceQuery(). 99 SetAccountID(env.OperatorID). 100 Execute(env.Client) 101 require.NoError(t, err) 102 103 require.Equal(t, uint64(1_000_000-tokenClaimAirdropTransferAmount), operatorBalance.Tokens.Get(tokenID)) 104 require.Equal(t, uint64(8), operatorBalance.Tokens.Get(nftID)) 105 } 106 107 func TestIntegrationTokenClaimAirdropMultipleReceivers(t *testing.T) { 108 env := NewIntegrationTestEnv(t) 109 defer CloseIntegrationTestEnv(env, nil) 110 111 // Create fungible token 112 tokenID, err := createFungibleToken(&env) 113 require.NoError(t, err) 114 115 // Create nft 116 nftID, err := createNft(&env) 117 require.NoError(t, err) 118 119 // Mint some NFTs 120 txResponse, err := NewTokenMintTransaction(). 121 SetTokenID(nftID). 122 SetMetadatas(mintMetadata). 123 Execute(env.Client) 124 require.NoError(t, err) 125 126 receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client) 127 require.NoError(t, err) 128 nftSerials := receipt.SerialNumbers 129 130 // Create receiver1 131 receiver1, receiver1Key, err := createAccount(&env) 132 require.NoError(t, err) 133 134 // Create receiver2 135 receiver2, receiver2Key, err := createAccount(&env) 136 require.NoError(t, err) 137 138 // Airdrop the tokens to both 139 airdropTx, err := NewTokenAirdropTransaction(). 140 AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, receiver1). 141 AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, receiver1). 142 AddTokenTransfer(tokenID, receiver1, tokenClaimAirdropTransferAmount). 143 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 144 AddNftTransfer(nftID.Nft(nftSerials[2]), env.OperatorID, receiver2). 145 AddNftTransfer(nftID.Nft(nftSerials[3]), env.OperatorID, receiver2). 146 AddTokenTransfer(tokenID, receiver2, tokenClaimAirdropTransferAmount). 147 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 148 Execute(env.Client) 149 require.NoError(t, err) 150 151 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 152 require.NoError(t, err) 153 154 // Verify the txn record 155 assert.Equal(t, 6, len(record.PendingAirdropRecords)) 156 157 // Claim the tokens signing with receiver1 and receiver2 158 claimTx, err := NewTokenClaimAirdropTransaction(). 159 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 160 AddPendingAirdropId(record.PendingAirdropRecords[1].GetPendingAirdropId()). 161 AddPendingAirdropId(record.PendingAirdropRecords[2].GetPendingAirdropId()). 162 AddPendingAirdropId(record.PendingAirdropRecords[3].GetPendingAirdropId()). 163 AddPendingAirdropId(record.PendingAirdropRecords[4].GetPendingAirdropId()). 164 AddPendingAirdropId(record.PendingAirdropRecords[5].GetPendingAirdropId()). 165 FreezeWith(env.Client) 166 require.NoError(t, err) 167 168 claimResp, err := claimTx.Sign(receiver1Key).Sign(receiver2Key).Execute(env.Client) 169 require.NoError(t, err) 170 171 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 172 require.NoError(t, err) 173 174 // Verify the receiver1 holds the tokens via query 175 reciverBalance, err := NewAccountBalanceQuery(). 176 SetAccountID(receiver1). 177 Execute(env.Client) 178 require.NoError(t, err) 179 180 require.Equal(t, uint64(tokenClaimAirdropTransferAmount), reciverBalance.Tokens.Get(tokenID)) 181 require.Equal(t, uint64(2), reciverBalance.Tokens.Get(nftID)) 182 183 // Verify the receiver2 holds the tokens via query 184 reciverBalance, err = NewAccountBalanceQuery(). 185 SetAccountID(receiver2). 186 Execute(env.Client) 187 require.NoError(t, err) 188 189 require.Equal(t, uint64(tokenClaimAirdropTransferAmount), reciverBalance.Tokens.Get(tokenID)) 190 require.Equal(t, uint64(2), reciverBalance.Tokens.Get(nftID)) 191 192 // Verify the operator does not hold the tokens 193 operatorBalance, err := NewAccountBalanceQuery(). 194 SetAccountID(env.OperatorID). 195 Execute(env.Client) 196 require.NoError(t, err) 197 198 require.Equal(t, uint64(1_000_000-tokenClaimAirdropTransferAmount*2), operatorBalance.Tokens.Get(tokenID)) 199 require.Equal(t, uint64(6), operatorBalance.Tokens.Get(nftID)) 200 201 } 202 203 func TestIntegrationTokenClaimAirdropMultipleAirdropTxns(t *testing.T) { 204 env := NewIntegrationTestEnv(t) 205 defer CloseIntegrationTestEnv(env, nil) 206 207 // Create fungible token 208 tokenID, err := createFungibleToken(&env) 209 require.NoError(t, err) 210 211 // Create nft 212 nftID, err := createNft(&env) 213 require.NoError(t, err) 214 215 // Mint some NFTs 216 txResponse, err := NewTokenMintTransaction(). 217 SetTokenID(nftID). 218 SetMetadatas(mintMetadata). 219 Execute(env.Client) 220 require.NoError(t, err) 221 222 receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client) 223 require.NoError(t, err) 224 nftSerials := receipt.SerialNumbers 225 226 // Create receiver 227 receiver, receiverKey, err := createAccount(&env) 228 require.NoError(t, err) 229 230 // Airdrop some of the tokens 231 airdropTx, err := NewTokenAirdropTransaction(). 232 AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, receiver). 233 Execute(env.Client) 234 require.NoError(t, err) 235 236 record1, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 237 require.NoError(t, err) 238 239 // Airdrop some of the tokens 240 airdropTx, err = NewTokenAirdropTransaction(). 241 AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, receiver). 242 Execute(env.Client) 243 require.NoError(t, err) 244 245 record2, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 246 require.NoError(t, err) 247 248 // Airdrop some of the tokens 249 airdropTx, err = NewTokenAirdropTransaction(). 250 AddTokenTransfer(tokenID, receiver, tokenClaimAirdropTransferAmount). 251 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 252 Execute(env.Client) 253 require.NoError(t, err) 254 255 record3, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 256 require.NoError(t, err) 257 258 // Collect pending airdrop IDs into a slice 259 pendingAirdrop1 := record1.PendingAirdropRecords[0].GetPendingAirdropId() 260 pendingAirdrop2 := record2.PendingAirdropRecords[0].GetPendingAirdropId() 261 pendingAirdrop3 := record3.PendingAirdropRecords[0].GetPendingAirdropId() 262 pendingAirdropIDs := make([]*PendingAirdropId, 0) 263 pendingAirdropIDs = append(pendingAirdropIDs, &pendingAirdrop1) 264 pendingAirdropIDs = append(pendingAirdropIDs, &pendingAirdrop2) 265 pendingAirdropIDs = append(pendingAirdropIDs, &pendingAirdrop3) 266 267 // Claim the all the tokens with the receiver 268 claimTx, err := NewTokenClaimAirdropTransaction(). 269 SetPendingAirdropIds(pendingAirdropIDs). 270 FreezeWith(env.Client) 271 require.NoError(t, err) 272 273 claimResp, err := claimTx.Sign(receiverKey).Execute(env.Client) 274 require.NoError(t, err) 275 276 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 277 require.NoError(t, err) 278 279 // Verify the receiver holds the tokens via query 280 reciverBalance, err := NewAccountBalanceQuery(). 281 SetAccountID(receiver). 282 Execute(env.Client) 283 require.NoError(t, err) 284 285 require.Equal(t, uint64(tokenClaimAirdropTransferAmount), reciverBalance.Tokens.Get(tokenID)) 286 require.Equal(t, uint64(2), reciverBalance.Tokens.Get(nftID)) 287 288 // Verify the operator does not hold the tokens 289 operatorBalance, err := NewAccountBalanceQuery(). 290 SetAccountID(env.OperatorID). 291 Execute(env.Client) 292 require.NoError(t, err) 293 294 require.Equal(t, uint64(1_000_000-tokenClaimAirdropTransferAmount), operatorBalance.Tokens.Get(tokenID)) 295 require.Equal(t, uint64(8), operatorBalance.Tokens.Get(nftID)) 296 } 297 298 func TestIntegrationTokenClaimAirdropCannotClaimNonExistingAirdrop(t *testing.T) { 299 env := NewIntegrationTestEnv(t) 300 defer CloseIntegrationTestEnv(env, nil) 301 302 // Create fungible token 303 tokenID, err := createFungibleToken(&env) 304 require.NoError(t, err) 305 306 // Create receiver 307 receiver, _, err := createAccount(&env) 308 require.NoError(t, err) 309 310 // Airdrop the tokens 311 airdropTx, err := NewTokenAirdropTransaction(). 312 AddTokenTransfer(tokenID, receiver, tokenClaimAirdropTransferAmount). 313 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 314 Execute(env.Client) 315 require.NoError(t, err) 316 317 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 318 require.NoError(t, err) 319 320 // Claim the tokens with the operator which does not have pending airdrops 321 claimResp, err := NewTokenClaimAirdropTransaction(). 322 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 323 Execute(env.Client) 324 require.NoError(t, err) 325 326 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 327 require.ErrorContains(t, err, "INVALID_SIGNATURE") 328 } 329 330 func TestIntegrationTokenClaimAirdropCannotClaimAlreadyClaimedAirdrop(t *testing.T) { 331 env := NewIntegrationTestEnv(t) 332 defer CloseIntegrationTestEnv(env, nil) 333 334 // Create fungible token 335 tokenID, err := createFungibleToken(&env) 336 require.NoError(t, err) 337 338 // Create receiver 339 receiver, receiverKey, err := createAccount(&env) 340 require.NoError(t, err) 341 342 // Airdrop the tokens 343 airdropTx, err := NewTokenAirdropTransaction(). 344 AddTokenTransfer(tokenID, receiver, tokenClaimAirdropTransferAmount). 345 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 346 Execute(env.Client) 347 require.NoError(t, err) 348 349 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 350 require.NoError(t, err) 351 352 // Claim the tokens with the receiver 353 claimTx, err := NewTokenClaimAirdropTransaction(). 354 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 355 FreezeWith(env.Client) 356 require.NoError(t, err) 357 358 claimResp, err := claimTx.Sign(receiverKey).Execute(env.Client) 359 require.NoError(t, err) 360 361 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 362 require.NoError(t, err) 363 364 // Claim the tokens with the receiver again 365 claimTx, err = NewTokenClaimAirdropTransaction(). 366 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 367 FreezeWith(env.Client) 368 require.NoError(t, err) 369 370 claimResp, err = claimTx.Sign(receiverKey).Execute(env.Client) 371 require.NoError(t, err) 372 373 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 374 require.ErrorContains(t, err, "INVALID_PENDING_AIRDROP_ID") 375 } 376 377 func TestIntegrationTokenClaimAirdropCannotClaimWithEmptyPendingAirdrops(t *testing.T) { 378 env := NewIntegrationTestEnv(t) 379 defer CloseIntegrationTestEnv(env, nil) 380 381 // Claim the tokens with the receiver without setting pendingAirdropIds 382 _, err := NewTokenClaimAirdropTransaction(). 383 Execute(env.Client) 384 require.ErrorContains(t, err, "EMPTY_PENDING_AIRDROP_ID_LIST") 385 } 386 387 func TestIntegrationTokenClaimAirdropCannotClaimWithDupblicateEntries(t *testing.T) { 388 env := NewIntegrationTestEnv(t) 389 defer CloseIntegrationTestEnv(env, nil) 390 391 // Create fungible token 392 tokenID, err := createFungibleToken(&env) 393 require.NoError(t, err) 394 395 // Create receiver 396 receiver, receiverKey, err := createAccount(&env) 397 require.NoError(t, err) 398 399 // Airdrop the tokens 400 airdropTx, err := NewTokenAirdropTransaction(). 401 AddTokenTransfer(tokenID, receiver, tokenClaimAirdropTransferAmount). 402 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 403 Execute(env.Client) 404 require.NoError(t, err) 405 406 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 407 require.NoError(t, err) 408 409 // Claim the tokens with duplicate pending airdrop token ids 410 claimTx, err := NewTokenClaimAirdropTransaction(). 411 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 412 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 413 FreezeWith(env.Client) 414 require.NoError(t, err) 415 416 _, err = claimTx.Sign(receiverKey).Execute(env.Client) 417 require.ErrorContains(t, err, "PENDING_AIRDROP_ID_REPEATED") 418 } 419 420 func TestIntegrationTokenClaimAirdropCannotClaimWithPausedToken(t *testing.T) { 421 env := NewIntegrationTestEnv(t) 422 defer CloseIntegrationTestEnv(env, nil) 423 424 // Create fungible token 425 tokenID, err := createFungibleToken(&env) 426 require.NoError(t, err) 427 428 // Create receiver 429 receiver, receiverKey, err := createAccount(&env) 430 require.NoError(t, err) 431 432 // Airdrop the tokens 433 airdropTx, err := NewTokenAirdropTransaction(). 434 AddTokenTransfer(tokenID, receiver, tokenClaimAirdropTransferAmount). 435 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 436 Execute(env.Client) 437 require.NoError(t, err) 438 439 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 440 require.NoError(t, err) 441 442 // Pause the token 443 pauseResp, err := NewTokenPauseTransaction().SetTokenID(tokenID).Execute(env.Client) 444 require.NoError(t, err) 445 _, err = pauseResp.SetValidateStatus(true).GetReceipt(env.Client) 446 require.NoError(t, err) 447 448 // Claim the tokens with receiver 449 claimTx, err := NewTokenClaimAirdropTransaction(). 450 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 451 FreezeWith(env.Client) 452 require.NoError(t, err) 453 454 claimResp, err := claimTx.Sign(receiverKey).Execute(env.Client) 455 require.NoError(t, err) 456 457 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 458 require.ErrorContains(t, err, "TOKEN_IS_PAUSED") 459 } 460 461 func TestIntegrationTokenClaimAirdropCannotClaimWithDeletedToken(t *testing.T) { 462 env := NewIntegrationTestEnv(t) 463 defer CloseIntegrationTestEnv(env, nil) 464 465 // Create fungible token 466 tokenID, err := createFungibleToken(&env) 467 require.NoError(t, err) 468 469 // Create receiver 470 receiver, receiverKey, err := createAccount(&env) 471 require.NoError(t, err) 472 473 // Airdrop the tokens 474 airdropTx, err := NewTokenAirdropTransaction(). 475 AddTokenTransfer(tokenID, receiver, tokenClaimAirdropTransferAmount). 476 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 477 Execute(env.Client) 478 require.NoError(t, err) 479 480 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 481 require.NoError(t, err) 482 483 // Delete the token 484 deleteResp, err := NewTokenDeleteTransaction().SetTokenID(tokenID).Execute(env.Client) 485 require.NoError(t, err) 486 _, err = deleteResp.SetValidateStatus(true).GetReceipt(env.Client) 487 require.NoError(t, err) 488 489 // Claim the tokens with receiver 490 claimTx, err := NewTokenClaimAirdropTransaction(). 491 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 492 FreezeWith(env.Client) 493 require.NoError(t, err) 494 495 claimResp, err := claimTx.Sign(receiverKey).Execute(env.Client) 496 require.NoError(t, err) 497 498 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 499 require.ErrorContains(t, err, "TOKEN_WAS_DELETED") 500 } 501 502 func TestIntegrationTokenClaimAirdropCannotClaimWithFrozenToken(t *testing.T) { 503 env := NewIntegrationTestEnv(t) 504 defer CloseIntegrationTestEnv(env, nil) 505 506 // Create fungible token 507 tokenID, err := createFungibleToken(&env) 508 require.NoError(t, err) 509 510 // Create receiver 511 receiver, receiverKey, err := createAccount(&env) 512 require.NoError(t, err) 513 514 // Airdrop the tokens 515 airdropTx, err := NewTokenAirdropTransaction(). 516 AddTokenTransfer(tokenID, receiver, tokenClaimAirdropTransferAmount). 517 AddTokenTransfer(tokenID, env.OperatorID, -tokenClaimAirdropTransferAmount). 518 Execute(env.Client) 519 require.NoError(t, err) 520 521 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 522 require.NoError(t, err) 523 524 // Associate the token 525 associateTx, err := NewTokenAssociateTransaction().AddTokenID(tokenID).SetAccountID(receiver).FreezeWith(env.Client) 526 require.NoError(t, err) 527 associateResp, err := associateTx.Sign(receiverKey).Execute(env.Client) 528 require.NoError(t, err) 529 _, err = associateResp.SetValidateStatus(true).GetReceipt(env.Client) 530 require.NoError(t, err) 531 532 // Freeze the token 533 freezeResp, err := NewTokenFreezeTransaction().SetTokenID(tokenID).SetAccountID(receiver).Execute(env.Client) 534 require.NoError(t, err) 535 _, err = freezeResp.SetValidateStatus(true).GetReceipt(env.Client) 536 require.NoError(t, err) 537 538 // Claim the tokens with receiver 539 claimTx, err := NewTokenClaimAirdropTransaction(). 540 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 541 FreezeWith(env.Client) 542 require.NoError(t, err) 543 544 claimResp, err := claimTx.Sign(receiverKey).Execute(env.Client) 545 require.NoError(t, err) 546 547 _, err = claimResp.SetValidateStatus(true).GetReceipt(env.Client) 548 require.ErrorContains(t, err, "ACCOUNT_FROZEN_FOR_TOKEN") 549 }