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

     1  //go:build all || e2e
     2  // +build all e2e
     3  
     4  package hedera
     5  
     6  import (
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  /*-
    15   *
    16   * Hedera Go SDK
    17   *
    18   * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
    19   *
    20   * Licensed under the Apache License, Version 2.0 (the "License");
    21   * you may not use this file except in compliance with the License.
    22   * You may obtain a copy of the License at
    23   *
    24   *      http://www.apache.org/licenses/LICENSE-2.0
    25   *
    26   * Unless required by applicable law or agreed to in writing, software
    27   * distributed under the License is distributed on an "AS IS" BASIS,
    28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    29   * See the License for the specific language governing permissions and
    30   * limitations under the License.
    31   *
    32   */
    33  
    34  func TestTokenUpdateNftsUpdatesMetadata(t *testing.T) {
    35  	env := NewIntegrationTestEnv(t)
    36  
    37  	// create supply key
    38  	supplyKey, err := PrivateKeyGenerateEd25519()
    39  	require.NoError(t, err)
    40  	supplyPublicKey := supplyKey.PublicKey()
    41  
    42  	// create metadata key
    43  	metadataKey, err := PrivateKeyGenerateEd25519()
    44  	require.NoError(t, err)
    45  	metadataPublicKey := metadataKey.PublicKey()
    46  
    47  	nftCount := 4
    48  	// create metadata list for all NFTs
    49  	mintMetadata := generateNftMetadata([]byte{4, 2, 0}, nftCount)
    50  	updatedMetadata := []byte{6, 9}
    51  	// create updated metadata list  for all NFTs
    52  	updatedMetadataList := generateNftMetadata(updatedMetadata, nftCount/2)
    53  
    54  	// create token with metadata key
    55  	tokenID := createTokenWithMetadataKey(t, &env, &metadataPublicKey, &supplyPublicKey)
    56  
    57  	// mint tokens using the metadata list
    58  	tokenMintTx, _ := NewTokenMintTransaction().
    59  		SetMetadatas(mintMetadata).
    60  		SetTokenID(tokenID).
    61  		FreezeWith(env.Client)
    62  	tx, err := tokenMintTx.Sign(supplyKey).Execute(env.Client)
    63  	require.NoError(t, err)
    64  	receipt, err := tx.GetReceipt(env.Client)
    65  	require.NoError(t, err)
    66  	nftSerials := receipt.SerialNumbers
    67  
    68  	// verify the metadata is set in the new tokens
    69  	metadataListAfterMint := getMetadataList(t, &env, tokenID, nftSerials)
    70  
    71  	assert.True(t, reflect.DeepEqual(metadataListAfterMint, mintMetadata), "metadata after minting should match initial metadata")
    72  
    73  	// update nft metadata for half of the NFTs
    74  	_, err = updateNftMetadata(t, &env, tokenID, nftSerials[:nftCount/2], updatedMetadata, &metadataKey)
    75  	require.NoError(t, err)
    76  
    77  	// verify the metadata is updated
    78  	metadataListAfterUpdate := getMetadataList(t, &env, tokenID, nftSerials[:nftCount/2])
    79  	assert.True(t, reflect.DeepEqual(metadataListAfterUpdate, updatedMetadataList), "updated metadata should match expected updated metadata")
    80  
    81  	// verify the remaining NFTs' metadata is unchanged
    82  	metadataList := getMetadataList(t, &env, tokenID, nftSerials[nftCount/2:])
    83  
    84  	assert.True(t, reflect.DeepEqual(metadataList, mintMetadata[nftCount/2:]), "remaining NFTs' metadata should remain unchanged")
    85  }
    86  
    87  func TestCanUpdateEmptyNFTMetadata(t *testing.T) {
    88  	env := NewIntegrationTestEnv(t)
    89  
    90  	// create supply key
    91  	supplyKey, err := PrivateKeyGenerateEd25519()
    92  	require.NoError(t, err)
    93  	supplyPublicKey := supplyKey.PublicKey()
    94  
    95  	// Generate metadata key
    96  	metadataKey, err := PrivateKeyGenerateEd25519()
    97  	require.NoError(t, err)
    98  	metadataPublicKey := metadataKey.PublicKey()
    99  
   100  	nftCount := 4
   101  	mintMetadata := generateNftMetadata([]byte{4, 2, 0}, nftCount)
   102  	updatedMetadata := make([]byte, 0)
   103  	updatedMetadataList := make([][]byte, 4)
   104  
   105  	// Create a token with a metadata key
   106  	tokenID := createTokenWithMetadataKey(t, &env, &metadataPublicKey, &supplyPublicKey)
   107  
   108  	// Mint tokens
   109  	tokenMintTx, _ := NewTokenMintTransaction().
   110  		SetMetadatas(mintMetadata).
   111  		SetTokenID(tokenID).
   112  		FreezeWith(env.Client)
   113  	tx, err := tokenMintTx.Sign(supplyKey).Execute(env.Client)
   114  	require.NoError(t, err)
   115  	receipt, err := tx.GetReceipt(env.Client)
   116  	require.NoError(t, err)
   117  	nftSerials := receipt.SerialNumbers
   118  
   119  	metadataListAfterMint := getMetadataList(t, &env, tokenID, nftSerials)
   120  	assert.Equal(t, mintMetadata, metadataListAfterMint, "metadata after minting should match initial metadata")
   121  
   122  	// Update metadata for all NFTs
   123  	_, err = updateNftMetadata(t, &env, tokenID, nftSerials, updatedMetadata, &metadataKey)
   124  	require.NoError(t, err)
   125  
   126  	// Verify updated metadata for NFTs
   127  	metadataListAfterUpdate := getMetadataList(t, &env, tokenID, nftSerials)
   128  	assert.Equal(t, updatedMetadataList, metadataListAfterUpdate, "updated metadata should match expected updated metadata")
   129  }
   130  
   131  func TestCannotUpdateNFTMetadataWhenKeyIsNotSet(t *testing.T) {
   132  	env := NewIntegrationTestEnv(t)
   133  
   134  	// create supply key
   135  	supplyKey, err := PrivateKeyGenerateEd25519()
   136  	require.NoError(t, err)
   137  	supplyPublicKey := supplyKey.PublicKey()
   138  
   139  	// Generate metadata key
   140  	metadataKey, err := PrivateKeyGenerateEd25519()
   141  	require.NoError(t, err)
   142  
   143  	nftCount := 4
   144  	mintMetadata := generateNftMetadata([]byte{4, 2, 0}, nftCount)
   145  	updatedMetadata := []byte{6, 9}
   146  
   147  	// Create a token without a metadata key
   148  	tokenID := createTokenWithMetadataKey(t, &env, nil, &supplyPublicKey)
   149  
   150  	// Mint tokens
   151  	tokenMintTx, _ := NewTokenMintTransaction().
   152  		SetMetadatas(mintMetadata).
   153  		SetTokenID(tokenID).
   154  		FreezeWith(env.Client)
   155  	tx, err := tokenMintTx.Sign(supplyKey).Execute(env.Client)
   156  	require.NoError(t, err)
   157  	receipt, err := tx.GetReceipt(env.Client)
   158  	require.NoError(t, err)
   159  	nftSerials := receipt.SerialNumbers
   160  
   161  	metadataListAfterMint := getMetadataList(t, &env, tokenID, nftSerials)
   162  	assert.Equal(t, mintMetadata, metadataListAfterMint, "metadata after minting should match initial metadata")
   163  
   164  	// Update metadata for the first half of the NFTs
   165  	_, err = updateNftMetadata(t, &env, tokenID, nftSerials[:nftCount/2], updatedMetadata, &metadataKey)
   166  	require.Error(t, err)
   167  }
   168  
   169  func TestCannotUpdateNFTMetadataWhenTransactionIsNotSignedWithMetadataKey(t *testing.T) {
   170  	env := NewIntegrationTestEnv(t)
   171  
   172  	// create supply key
   173  	supplyKey, err := PrivateKeyGenerateEd25519()
   174  	require.NoError(t, err)
   175  	supplyPublicKey := supplyKey.PublicKey()
   176  
   177  	// Generate metadata key
   178  	metadataKey, err := PrivateKeyGenerateEd25519()
   179  	require.NoError(t, err)
   180  	metadataPublicKey := metadataKey.PublicKey()
   181  
   182  	nftCount := 4
   183  	mintMetadata := generateNftMetadata([]byte{4, 2, 0}, nftCount)
   184  	updatedMetadata := []byte{6, 9}
   185  
   186  	// Create a token with a metadata key
   187  	tokenID := createTokenWithMetadataKey(t, &env, &metadataPublicKey, &supplyPublicKey)
   188  
   189  	// Mint tokens
   190  	tokenMintTx, _ := NewTokenMintTransaction().
   191  		SetMetadatas(mintMetadata).
   192  		SetTokenID(tokenID).
   193  		FreezeWith(env.Client)
   194  	tx, err := tokenMintTx.Sign(supplyKey).Execute(env.Client)
   195  	require.NoError(t, err)
   196  	receipt, err := tx.GetReceipt(env.Client)
   197  	require.NoError(t, err)
   198  	nftSerials := receipt.SerialNumbers
   199  
   200  	// Assert this will fail
   201  	_, err = updateNftMetadata(t, &env, tokenID, nftSerials, updatedMetadata, &env.OperatorKey)
   202  	require.Error(t, err)
   203  
   204  	_, err = updateNftMetadata(t, &env, tokenID, nftSerials, updatedMetadata, nil)
   205  	require.Error(t, err)
   206  }
   207  
   208  // Utility functions
   209  func createTokenWithMetadataKey(t *testing.T, env *IntegrationTestEnv, metadataKey *PublicKey, supplyKey *PublicKey) TokenID {
   210  	var tokenCreateTx *TokenCreateTransaction
   211  	if metadataKey == nil {
   212  		tokenCreateTx = NewTokenCreateTransaction().
   213  			SetNodeAccountIDs(env.NodeAccountIDs).
   214  			SetTokenName("ffff").
   215  			SetTokenSymbol("F").
   216  			SetTokenType(TokenTypeNonFungibleUnique).
   217  			SetTreasuryAccountID(env.Client.GetOperatorAccountID()).
   218  			SetAdminKey(env.Client.GetOperatorPublicKey()).
   219  			SetSupplyKey(supplyKey)
   220  	} else {
   221  		tokenCreateTx = NewTokenCreateTransaction().
   222  			SetNodeAccountIDs(env.NodeAccountIDs).
   223  			SetTokenName("ffff").
   224  			SetTokenSymbol("F").
   225  			SetTokenType(TokenTypeNonFungibleUnique).
   226  			SetTreasuryAccountID(env.Client.GetOperatorAccountID()).
   227  			SetAdminKey(env.Client.GetOperatorPublicKey()).
   228  			SetSupplyKey(supplyKey).
   229  			SetMetadataKey(metadataKey)
   230  	}
   231  
   232  	tx, err := tokenCreateTx.Execute(env.Client)
   233  	require.NoError(t, err)
   234  
   235  	receipt, err := tx.GetReceipt(env.Client)
   236  	require.NoError(t, err)
   237  
   238  	return *receipt.TokenID
   239  }
   240  
   241  func updateNftMetadata(t *testing.T, env *IntegrationTestEnv, tokenID TokenID, serials []int64, updatedMetadata []byte, metadataKey *PrivateKey) (*TransactionReceipt, error) {
   242  	var tokenUpdateNftsTx *TokenUpdateNfts
   243  	if metadataKey == nil {
   244  		tokenUpdateNftsTx = NewTokenUpdateNftsTransaction().
   245  			SetTokenID(tokenID).
   246  			SetSerialNumbers(serials).
   247  			SetMetadata(updatedMetadata)
   248  	} else {
   249  		frozenTx, err := NewTokenUpdateNftsTransaction().
   250  			SetTokenID(tokenID).
   251  			SetSerialNumbers(serials).
   252  			SetMetadata(updatedMetadata).
   253  			FreezeWith(env.Client)
   254  		require.NoError(t, err)
   255  
   256  		tokenUpdateNftsTx = frozenTx.Sign(*metadataKey)
   257  	}
   258  
   259  	tx, err := tokenUpdateNftsTx.Execute(env.Client)
   260  	require.NoError(t, err)
   261  
   262  	receipt, err := tx.GetReceipt(env.Client)
   263  
   264  	return &receipt, err
   265  }
   266  
   267  func getMetadataList(t *testing.T, env *IntegrationTestEnv, tokenID TokenID, nftSerials []int64) [][]byte {
   268  	var metadataList [][]byte
   269  
   270  	for _, serial := range nftSerials {
   271  		nftID := NftID{
   272  			TokenID:      tokenID,
   273  			SerialNumber: serial,
   274  		}
   275  
   276  		tokenNftInfoQuery := NewTokenNftInfoQuery().
   277  			SetNodeAccountIDs(env.NodeAccountIDs).
   278  			SetNftID(nftID)
   279  
   280  		nftInfo, err := tokenNftInfoQuery.Execute(env.Client)
   281  		require.NoError(t, err)
   282  		metadataList = append(metadataList, nftInfo[0].Metadata)
   283  	}
   284  
   285  	return metadataList
   286  }
   287  
   288  func generateNftMetadata(data []byte, count int) [][]byte {
   289  	var metadataList [][]byte
   290  
   291  	for i := 0; i < count; i++ {
   292  		metadataList = append(metadataList, data)
   293  	}
   294  
   295  	return metadataList
   296  }