github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/token_cancel_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 tokenCancelAirdropTransferAmount = 100 34 35 func TestIntegrationTokenCancelAirdropCanExecute(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 59 receiver, _, 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, tokenCancelAirdropTransferAmount). 67 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 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 // Cancel the tokens with the operator 75 cancelTx, err := NewTokenCancelAirdropTransaction(). 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 cancelResp, err := cancelTx.Sign(env.OperatorKey).Execute(env.Client) 83 require.NoError(t, err) 84 85 _, err = cancelResp.SetValidateStatus(true).GetReceipt(env.Client) 86 require.NoError(t, err) 87 88 // Verify the operator does hold the tokens 89 operatorBalance, err := NewAccountBalanceQuery(). 90 SetAccountID(env.OperatorID). 91 Execute(env.Client) 92 require.NoError(t, err) 93 94 require.Equal(t, uint64(1_000_000), operatorBalance.Tokens.Get(tokenID)) 95 require.Equal(t, uint64(10), operatorBalance.Tokens.Get(nftID)) 96 } 97 98 func TestIntegrationTokenCancelAirdropMultipleReceivers(t *testing.T) { 99 env := NewIntegrationTestEnv(t) 100 defer CloseIntegrationTestEnv(env, nil) 101 102 // Create fungible token 103 tokenID, err := createFungibleToken(&env) 104 require.NoError(t, err) 105 106 // Create nft 107 nftID, err := createNft(&env) 108 require.NoError(t, err) 109 110 // Mint some NFTs 111 txResponse, err := NewTokenMintTransaction(). 112 SetTokenID(nftID). 113 SetMetadatas(mintMetadata). 114 Execute(env.Client) 115 require.NoError(t, err) 116 117 receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client) 118 require.NoError(t, err) 119 nftSerials := receipt.SerialNumbers 120 121 // Create receiver1 122 receiver1, receiver1Key, err := createAccount(&env) 123 require.NoError(t, err) 124 125 // Create receiver2 126 receiver2, receiver2Key, err := createAccount(&env) 127 require.NoError(t, err) 128 129 // Airdrop the tokens to both 130 airdropTx, err := NewTokenAirdropTransaction(). 131 AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, receiver1). 132 AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, receiver1). 133 AddTokenTransfer(tokenID, receiver1, tokenCancelAirdropTransferAmount). 134 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 135 AddNftTransfer(nftID.Nft(nftSerials[2]), env.OperatorID, receiver2). 136 AddNftTransfer(nftID.Nft(nftSerials[3]), env.OperatorID, receiver2). 137 AddTokenTransfer(tokenID, receiver2, tokenCancelAirdropTransferAmount). 138 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 139 Execute(env.Client) 140 require.NoError(t, err) 141 142 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 143 require.NoError(t, err) 144 145 // Verify the txn record 146 assert.Equal(t, 6, len(record.PendingAirdropRecords)) 147 148 // Cancel the tokens signing with receiver1 and receiver2 149 cancelTx, err := NewTokenCancelAirdropTransaction(). 150 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 151 AddPendingAirdropId(record.PendingAirdropRecords[1].GetPendingAirdropId()). 152 AddPendingAirdropId(record.PendingAirdropRecords[2].GetPendingAirdropId()). 153 AddPendingAirdropId(record.PendingAirdropRecords[3].GetPendingAirdropId()). 154 AddPendingAirdropId(record.PendingAirdropRecords[4].GetPendingAirdropId()). 155 AddPendingAirdropId(record.PendingAirdropRecords[5].GetPendingAirdropId()). 156 FreezeWith(env.Client) 157 require.NoError(t, err) 158 159 cancelResp, err := cancelTx.Sign(receiver1Key).Sign(receiver2Key).Execute(env.Client) 160 require.NoError(t, err) 161 162 _, err = cancelResp.SetValidateStatus(true).GetReceipt(env.Client) 163 require.NoError(t, err) 164 165 // Verify the operator does hold the tokens 166 operatorBalance, err := NewAccountBalanceQuery(). 167 SetAccountID(env.OperatorID). 168 Execute(env.Client) 169 require.NoError(t, err) 170 171 require.Equal(t, uint64(1_000_000), operatorBalance.Tokens.Get(tokenID)) 172 require.Equal(t, uint64(10), operatorBalance.Tokens.Get(nftID)) 173 174 } 175 176 func TestIntegrationTokenCancelAirdropMultipleAirdropTxns(t *testing.T) { 177 env := NewIntegrationTestEnv(t) 178 defer CloseIntegrationTestEnv(env, nil) 179 180 // Create fungible token 181 tokenID, err := createFungibleToken(&env) 182 require.NoError(t, err) 183 184 // Create nft 185 nftID, err := createNft(&env) 186 require.NoError(t, err) 187 188 // Mint some NFTs 189 txResponse, err := NewTokenMintTransaction(). 190 SetTokenID(nftID). 191 SetMetadatas(mintMetadata). 192 Execute(env.Client) 193 require.NoError(t, err) 194 195 receipt, err := txResponse.SetValidateStatus(true).GetReceipt(env.Client) 196 require.NoError(t, err) 197 nftSerials := receipt.SerialNumbers 198 199 // Create receiver 200 receiver, _, err := createAccount(&env) 201 require.NoError(t, err) 202 203 // Airdrop some of the tokens 204 airdropTx, err := NewTokenAirdropTransaction(). 205 AddNftTransfer(nftID.Nft(nftSerials[0]), env.OperatorID, receiver). 206 Execute(env.Client) 207 require.NoError(t, err) 208 209 record1, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 210 require.NoError(t, err) 211 212 // Airdrop some of the tokens 213 airdropTx, err = NewTokenAirdropTransaction(). 214 AddNftTransfer(nftID.Nft(nftSerials[1]), env.OperatorID, receiver). 215 Execute(env.Client) 216 require.NoError(t, err) 217 218 record2, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 219 require.NoError(t, err) 220 221 // Airdrop some of the tokens 222 airdropTx, err = NewTokenAirdropTransaction(). 223 AddTokenTransfer(tokenID, receiver, tokenCancelAirdropTransferAmount). 224 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 225 Execute(env.Client) 226 require.NoError(t, err) 227 228 record3, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 229 require.NoError(t, err) 230 231 // Collect pending airdrop IDs into a slice 232 pendingAirdrop1 := record1.PendingAirdropRecords[0].GetPendingAirdropId() 233 pendingAirdrop2 := record2.PendingAirdropRecords[0].GetPendingAirdropId() 234 pendingAirdrop3 := record3.PendingAirdropRecords[0].GetPendingAirdropId() 235 pendingAirdropIDs := make([]*PendingAirdropId, 0) 236 pendingAirdropIDs = append(pendingAirdropIDs, &pendingAirdrop1) 237 pendingAirdropIDs = append(pendingAirdropIDs, &pendingAirdrop2) 238 pendingAirdropIDs = append(pendingAirdropIDs, &pendingAirdrop3) 239 240 // Cancel the all the tokens with the receiver 241 cancelTx, err := NewTokenCancelAirdropTransaction(). 242 SetPendingAirdropIds(pendingAirdropIDs). 243 FreezeWith(env.Client) 244 require.NoError(t, err) 245 246 cancelResp, err := cancelTx.Sign(env.OperatorKey).Execute(env.Client) 247 require.NoError(t, err) 248 249 _, err = cancelResp.SetValidateStatus(true).GetReceipt(env.Client) 250 require.NoError(t, err) 251 252 // Verify the receiver does not hold the tokens via query 253 reciverBalance, err := NewAccountBalanceQuery(). 254 SetAccountID(receiver). 255 Execute(env.Client) 256 require.NoError(t, err) 257 258 require.Equal(t, uint64(0), reciverBalance.Tokens.Get(tokenID)) 259 require.Equal(t, uint64(0), reciverBalance.Tokens.Get(nftID)) 260 261 // Verify the operator does hold the tokens 262 operatorBalance, err := NewAccountBalanceQuery(). 263 SetAccountID(env.OperatorID). 264 Execute(env.Client) 265 require.NoError(t, err) 266 267 require.Equal(t, uint64(1_000_000), operatorBalance.Tokens.Get(tokenID)) 268 require.Equal(t, uint64(10), operatorBalance.Tokens.Get(nftID)) 269 } 270 271 func TestIntegrationTokenCancelAirdropCannotCancelNonExistingAirdrop(t *testing.T) { 272 env := NewIntegrationTestEnv(t) 273 defer CloseIntegrationTestEnv(env, nil) 274 275 // Create fungible token 276 tokenID, err := createFungibleToken(&env) 277 require.NoError(t, err) 278 279 // Create receiver 280 receiver, _, err := createAccount(&env) 281 require.NoError(t, err) 282 // Create random account 283 randomAccount, _, err := createAccount(&env) 284 require.NoError(t, err) 285 286 // Airdrop the tokens 287 airdropTx, err := NewTokenAirdropTransaction(). 288 AddTokenTransfer(tokenID, receiver, tokenCancelAirdropTransferAmount). 289 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 290 Execute(env.Client) 291 require.NoError(t, err) 292 293 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 294 require.NoError(t, err) 295 296 // Cancel the tokens with the random account which has not created pending airdrops 297 _, err = NewTokenCancelAirdropTransaction(). 298 SetTransactionID(TransactionIDGenerate(randomAccount)). 299 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 300 Execute(env.Client) 301 require.ErrorContains(t, err, "INVALID_SIGNATURE") 302 } 303 304 func TestIntegrationTokenCancelAirdropCannotCancelAlreadyCanceledAirdrop(t *testing.T) { 305 env := NewIntegrationTestEnv(t) 306 defer CloseIntegrationTestEnv(env, nil) 307 308 // Create fungible token 309 tokenID, err := createFungibleToken(&env) 310 require.NoError(t, err) 311 312 // Create receiver 313 receiver, _, err := createAccount(&env) 314 require.NoError(t, err) 315 316 // Airdrop the tokens 317 airdropTx, err := NewTokenAirdropTransaction(). 318 AddTokenTransfer(tokenID, receiver, tokenCancelAirdropTransferAmount). 319 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 320 Execute(env.Client) 321 require.NoError(t, err) 322 323 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 324 require.NoError(t, err) 325 326 // Cancel the tokens with the operator 327 cancelTx, err := NewTokenCancelAirdropTransaction(). 328 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 329 FreezeWith(env.Client) 330 require.NoError(t, err) 331 332 cancelResp, err := cancelTx.Sign(env.OperatorKey).Execute(env.Client) 333 require.NoError(t, err) 334 335 _, err = cancelResp.SetValidateStatus(true).GetReceipt(env.Client) 336 require.NoError(t, err) 337 338 // Cancel the tokens with the operator again 339 cancelTx, err = NewTokenCancelAirdropTransaction(). 340 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 341 FreezeWith(env.Client) 342 require.NoError(t, err) 343 344 cancelResp, err = cancelTx.Sign(env.OperatorKey).Execute(env.Client) 345 require.NoError(t, err) 346 347 _, err = cancelResp.SetValidateStatus(true).GetReceipt(env.Client) 348 require.ErrorContains(t, err, "INVALID_PENDING_AIRDROP_ID") 349 } 350 351 func TestIntegrationTokenCancelAirdropCannotCancelWithEmptyPendingAirdrops(t *testing.T) { 352 env := NewIntegrationTestEnv(t) 353 defer CloseIntegrationTestEnv(env, nil) 354 355 // Cancel the tokens with the operator without setting pendingAirdropIds 356 _, err := NewTokenCancelAirdropTransaction(). 357 Execute(env.Client) 358 require.ErrorContains(t, err, "EMPTY_PENDING_AIRDROP_ID_LIST") 359 } 360 361 func TestIntegrationTokenCancelAirdropCannotCancelWithDupblicateEntries(t *testing.T) { 362 env := NewIntegrationTestEnv(t) 363 defer CloseIntegrationTestEnv(env, nil) 364 365 // Create fungible token 366 tokenID, err := createFungibleToken(&env) 367 require.NoError(t, err) 368 369 // Create receiver 370 receiver, _, err := createAccount(&env) 371 require.NoError(t, err) 372 373 // Airdrop the tokens 374 airdropTx, err := NewTokenAirdropTransaction(). 375 AddTokenTransfer(tokenID, receiver, tokenCancelAirdropTransferAmount). 376 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 377 Execute(env.Client) 378 require.NoError(t, err) 379 380 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 381 require.NoError(t, err) 382 383 // Cancel the tokens with duplicate pending airdrop token ids 384 cancelTx, err := NewTokenCancelAirdropTransaction(). 385 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 386 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 387 FreezeWith(env.Client) 388 require.NoError(t, err) 389 390 _, err = cancelTx.Sign(env.OperatorKey).Execute(env.Client) 391 require.ErrorContains(t, err, "PENDING_AIRDROP_ID_REPEATED") 392 } 393 394 func TestIntegrationTokenCancelAirdropCanCancelWithPausedToken(t *testing.T) { 395 env := NewIntegrationTestEnv(t) 396 defer CloseIntegrationTestEnv(env, nil) 397 398 // Create fungible token 399 tokenID, err := createFungibleToken(&env) 400 require.NoError(t, err) 401 402 // Create receiver 403 receiver, _, err := createAccount(&env) 404 require.NoError(t, err) 405 406 // Airdrop the tokens 407 airdropTx, err := NewTokenAirdropTransaction(). 408 AddTokenTransfer(tokenID, receiver, tokenCancelAirdropTransferAmount). 409 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 410 Execute(env.Client) 411 require.NoError(t, err) 412 413 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 414 require.NoError(t, err) 415 416 // Pause the token 417 pauseResp, err := NewTokenPauseTransaction().SetTokenID(tokenID).Execute(env.Client) 418 require.NoError(t, err) 419 _, err = pauseResp.SetValidateStatus(true).GetReceipt(env.Client) 420 require.NoError(t, err) 421 422 // Cancel the tokens with receiver 423 cancelTx, err := NewTokenCancelAirdropTransaction(). 424 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 425 FreezeWith(env.Client) 426 require.NoError(t, err) 427 428 cancelResp, err := cancelTx.Sign(env.OperatorKey).Execute(env.Client) 429 require.NoError(t, err) 430 431 _, err = cancelResp.SetValidateStatus(true).GetReceipt(env.Client) 432 require.NoError(t, err) 433 } 434 435 func TestIntegrationTokenCancelAirdropCanCancelWithDeletedToken(t *testing.T) { 436 env := NewIntegrationTestEnv(t) 437 defer CloseIntegrationTestEnv(env, nil) 438 439 // Create fungible token 440 tokenID, err := createFungibleToken(&env) 441 require.NoError(t, err) 442 443 // Create receiver 444 receiver, _, err := createAccount(&env) 445 require.NoError(t, err) 446 447 // Airdrop the tokens 448 airdropTx, err := NewTokenAirdropTransaction(). 449 AddTokenTransfer(tokenID, receiver, tokenCancelAirdropTransferAmount). 450 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 451 Execute(env.Client) 452 require.NoError(t, err) 453 454 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 455 require.NoError(t, err) 456 457 // Delete the token 458 deleteResp, err := NewTokenDeleteTransaction().SetTokenID(tokenID).Execute(env.Client) 459 require.NoError(t, err) 460 _, err = deleteResp.SetValidateStatus(true).GetReceipt(env.Client) 461 require.NoError(t, err) 462 463 // Cancel the tokens with receiver 464 cancelTx, err := NewTokenCancelAirdropTransaction(). 465 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 466 FreezeWith(env.Client) 467 require.NoError(t, err) 468 469 cancelResp, err := cancelTx.Sign(env.OperatorKey).Execute(env.Client) 470 require.NoError(t, err) 471 472 _, err = cancelResp.SetValidateStatus(true).GetReceipt(env.Client) 473 require.NoError(t, err) 474 } 475 476 func TestIntegrationTokenCancelAirdropCanCancelWithFrozenToken(t *testing.T) { 477 env := NewIntegrationTestEnv(t) 478 defer CloseIntegrationTestEnv(env, nil) 479 480 // Create fungible token 481 tokenID, err := createFungibleToken(&env) 482 require.NoError(t, err) 483 484 // Create receiver 485 receiver, receiverKey, err := createAccount(&env) 486 require.NoError(t, err) 487 488 // Airdrop the tokens 489 airdropTx, err := NewTokenAirdropTransaction(). 490 AddTokenTransfer(tokenID, receiver, tokenCancelAirdropTransferAmount). 491 AddTokenTransfer(tokenID, env.OperatorID, -tokenCancelAirdropTransferAmount). 492 Execute(env.Client) 493 require.NoError(t, err) 494 495 record, err := airdropTx.SetValidateStatus(true).GetRecord(env.Client) 496 require.NoError(t, err) 497 498 // Associate the token 499 associateTx, err := NewTokenAssociateTransaction().AddTokenID(tokenID).SetAccountID(receiver).FreezeWith(env.Client) 500 require.NoError(t, err) 501 associateResp, err := associateTx.Sign(receiverKey).Execute(env.Client) 502 require.NoError(t, err) 503 _, err = associateResp.SetValidateStatus(true).GetReceipt(env.Client) 504 require.NoError(t, err) 505 506 // Freeze the token 507 freezeTx, err := NewTokenFreezeTransaction().SetTokenID(tokenID).SetAccountID(receiver).FreezeWith(env.Client) 508 require.NoError(t, err) 509 freezeResp, err := freezeTx.Sign(receiverKey).Execute(env.Client) 510 _, err = freezeResp.SetValidateStatus(true).GetReceipt(env.Client) 511 require.NoError(t, err) 512 513 // Cancel the tokens with receiver 514 cancelTx, err := NewTokenCancelAirdropTransaction(). 515 AddPendingAirdropId(record.PendingAirdropRecords[0].GetPendingAirdropId()). 516 FreezeWith(env.Client) 517 require.NoError(t, err) 518 519 cancelResp, err := cancelTx.Sign(env.OperatorKey).Execute(env.Client) 520 require.NoError(t, err) 521 522 _, err = cancelResp.SetValidateStatus(true).GetReceipt(env.Client) 523 require.NoError(t, err) 524 }