Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: update metadata field of fungible and non-fungible tokens, and dynamic NFTs #2210

Merged
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
537797d
feature: mutable metadata fields for dynamic NFTs
svetoslav-nikol0v Mar 18, 2024
37b292d
update: TokenCreateTransaction class and related intergration test
svetoslav-nikol0v Mar 18, 2024
f04f644
update: TokenUpdateTransaction class and integration test
svetoslav-nikol0v Mar 18, 2024
49f00b8
update: TokenInfo class and integration test
svetoslav-nikol0v Mar 18, 2024
b7671e9
chore: formatting
svetoslav-nikol0v Mar 18, 2024
9c0351f
chore: formatting
svetoslav-nikol0v Mar 19, 2024
f45920b
update: example
svetoslav-nikol0v Mar 25, 2024
2ef1d89
update: integration tests
svetoslav-nikol0v Mar 25, 2024
2b19450
update: update examples
svetoslav-nikol0v Mar 26, 2024
8b2bb70
update: adding all integration tests
svetoslav-nikol0v Mar 26, 2024
8e01632
update: add tests for fungible token
svetoslav-nikol0v Mar 27, 2024
c86665c
update: integration tests
svetoslav-nikol0v Apr 17, 2024
0854410
update: unit tests
svetoslav-nikol0v Apr 18, 2024
4488817
chore: proto version
svetoslav-nikol0v Apr 18, 2024
8231dc5
update: examples for fungible token
svetoslav-nikol0v Apr 18, 2024
38ef737
update: integration tests
svetoslav-nikol0v Apr 18, 2024
9f128cd
chore: network tag
svetoslav-nikol0v Apr 18, 2024
f6cc669
chore: formatting
svetoslav-nikol0v Apr 18, 2024
5040397
update: examples
svetoslav-nikol0v Apr 19, 2024
70b4ea0
update: integration tests
svetoslav-nikol0v Apr 19, 2024
183b2b0
chore: network tag
svetoslav-nikol0v Apr 19, 2024
89bc33c
chore: network tag
svetoslav-nikol0v Apr 19, 2024
ee6053e
update: examples
svetoslav-nikol0v Apr 22, 2024
21deae3
chore: test change
svetoslav-nikol0v Apr 22, 2024
a18b596
chore: update network tag 0.49.0-alpha.5
svetoslav-nikol0v Apr 23, 2024
98602ff
update: protobufs
svetoslav-nikol0v Apr 24, 2024
93c7e43
update: proto package version
svetoslav-nikol0v Apr 24, 2024
be4ecab
update: examples
svetoslav-nikol0v Apr 24, 2024
f4c9173
Merge branch 'main' into 1733-add-hip-657-mutable-metadata-fields-for…
svetoslav-nikol0v Apr 24, 2024
68fa9c1
chore: formatting
svetoslav-nikol0v Apr 24, 2024
31f4612
update: codeowners
svetoslav-nikol0v Apr 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ async function main() {
.setCustomFees([nftCustomFee])
.setAdminKey(adminKey)
.setSupplyKey(supplyKey)
// .setPauseKey(pauseKey)
.setFreezeKey(freezeKey)
.setWipeKey(wipeKey)
.freezeWith(client)
Expand Down
104 changes: 104 additions & 0 deletions examples/update-fungible-token-metadata-with-admin-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {
TokenCreateTransaction,
TokenInfoQuery,
TokenType,
PrivateKey,
Client,
AccountId,
TokenUpdateTransaction,
} from "@hashgraph/sdk";
import dotenv from "dotenv";

dotenv.config();

/**
* @summary E2E-HIP-646 https://hips.hedera.com/hip/hip-646
* @description Update fungible token metadata with admin key
*/
async function main() {
if (
!process.env.OPERATOR_KEY ||
!process.env.OPERATOR_ID ||
!process.env.HEDERA_NETWORK
) {
throw new Error("Please set required keys in .env file.");
}

const operatorId = AccountId.fromString(process.env.OPERATOR_ID);
const operatorKey = PrivateKey.fromStringDer(process.env.OPERATOR_KEY);
const network = process.env.HEDERA_NETWORK;
const client = Client.forName(network).setOperator(operatorId, operatorKey);

// Generate a admin key
const adminKey = PrivateKey.generateED25519();
// Initial metadata
svetoslav-nikol0v marked this conversation as resolved.
Show resolved Hide resolved
const metadata = new Uint8Array([1]);
// New metadata
const newMetadata = new Uint8Array([1, 2]);

let tokenInfo;

try {
// Create a non fungible token
let createTokenTx = new TokenCreateTransaction()
.setTokenName("Test")
.setTokenSymbol("T")
.setMetadata(metadata)
.setTokenType(TokenType.FungibleCommon) // The same flow can be executed with a TokenType.NON_FUNGIBLE_UNIQUE (i.e. HIP-765)
.setDecimals(3)
.setInitialSupply(10000)
.setTreasuryAccountId(operatorId)
.setAdminKey(adminKey)
.freezeWith(client);

// Sign and execute create token transaction
const tokenCreateTxResponse = await (
await createTokenTx.sign(adminKey)
).execute(client);

// Get receipt for create token transaction
const tokenCreateTxReceipt =
await tokenCreateTxResponse.getReceipt(client);
console.log(
`Status of token create transction: ${tokenCreateTxReceipt.status.toString()}`,
);

// Get token id
const tokenId = tokenCreateTxReceipt.tokenId;
console.log(`Token id: ${tokenId.toString()}`);

// Get token info
tokenInfo = await new TokenInfoQuery()
.setTokenId(tokenId)
.execute(client);
console.log(`Token metadata:`, tokenInfo.metadata);

const tokenUpdateTx = new TokenUpdateTransaction()
.setTokenId(tokenId)
.setMetadata(newMetadata)
.freezeWith(client);

// Sign transactions with admin key and execute it
const tokenUpdateTxResponse = await (
await tokenUpdateTx.sign(adminKey)
).execute(client);

// Get receipt for token update transaction
const tokenUpdateTxReceipt =
await tokenUpdateTxResponse.getReceipt(client);
console.log(
`Status of token update transction: ${tokenUpdateTxReceipt.status.toString()}`,
);

tokenInfo = await new TokenInfoQuery()
.setTokenId(tokenId)
.execute(client);
console.log(`Token updated metadata:`, tokenInfo.metadata);
} catch (error) {
console.log(error);
}

client.close();
}

void main();
104 changes: 104 additions & 0 deletions examples/update-fungible-token-metadata-with-metadata-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {
TokenCreateTransaction,
TokenInfoQuery,
TokenType,
PrivateKey,
Client,
AccountId,
TokenUpdateTransaction,
} from "@hashgraph/sdk";
import dotenv from "dotenv";

dotenv.config();

/**
* @summary E2E-HIP-646 https://hips.hedera.com/hip/hip-646
* @description Update fungible token metadata with metadata key
*/
async function main() {
if (
!process.env.OPERATOR_KEY ||
!process.env.OPERATOR_ID ||
!process.env.HEDERA_NETWORK
) {
throw new Error("Please set required keys in .env file.");
}

const operatorId = AccountId.fromString(process.env.OPERATOR_ID);
const operatorKey = PrivateKey.fromStringDer(process.env.OPERATOR_KEY);
const network = process.env.HEDERA_NETWORK;
const client = Client.forName(network).setOperator(operatorId, operatorKey);

// Generate a metadata key
const metadataKey = PrivateKey.generateED25519();
// Initial metadata
const metadata = new Uint8Array([1]);
// New metadata
const newMetadata = new Uint8Array([1, 2]);

let tokenInfo;

try {
// Create a non fungible token
let createTokenTx = new TokenCreateTransaction()
.setTokenName("Test")
.setTokenSymbol("T")
.setMetadata(metadata)
.setTokenType(TokenType.FungibleCommon) // The same flow can be executed with a TokenType.NON_FUNGIBLE_UNIQUE (i.e. HIP-765)
.setDecimals(3)
.setInitialSupply(10000)
.setTreasuryAccountId(operatorId)
.setMetadataKey(metadataKey)
.freezeWith(client);

// Sign and execute create token transaction
const tokenCreateTxResponse = await (
await createTokenTx.sign(operatorKey)
).execute(client);

// Get receipt for create token transaction
const tokenCreateTxReceipt =
await tokenCreateTxResponse.getReceipt(client);
console.log(
`Status of token create transction: ${tokenCreateTxReceipt.status.toString()}`,
);

// Get token id
const tokenId = tokenCreateTxReceipt.tokenId;
console.log(`Token id: ${tokenId.toString()}`);

// Get token info
tokenInfo = await new TokenInfoQuery()
.setTokenId(tokenId)
.execute(client);
console.log(`Token metadata:`, tokenInfo.metadata);

const tokenUpdateTx = new TokenUpdateTransaction()
.setTokenId(tokenId)
.setMetadata(newMetadata)
.freezeWith(client);

// Sign transactions with metadata key and execute it
const tokenUpdateTxResponse = await (
await tokenUpdateTx.sign(metadataKey)
).execute(client);

// Get receipt for token update transaction
const tokenUpdateTxReceipt =
await tokenUpdateTxResponse.getReceipt(client);
console.log(
`Status of token update transction: ${tokenUpdateTxReceipt.status.toString()}`,
);

tokenInfo = await new TokenInfoQuery()
.setTokenId(tokenId)
.execute(client);
console.log(`Token updated metadata:`, tokenInfo.metadata);
} catch (error) {
console.log(error);
}

client.close();
}

void main();
178 changes: 178 additions & 0 deletions examples/update-nfts-metadata-of-non-fungible-token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import {
TokenCreateTransaction,
TokenInfoQuery,
TokenType,
PrivateKey,
Client,
AccountId,
TokenMintTransaction,
TokenNftsUpdateTransaction,
TokenNftInfoQuery,
NftId,
AccountCreateTransaction,
Hbar,
TransferTransaction,
TokenAssociateTransaction,
} from "@hashgraph/sdk";
import dotenv from "dotenv";

dotenv.config();

/**
* @summary E2E-HIP-657 https://hips.hedera.com/hip/hip-657
* @description Update nfts metadata of fungible token with metadata key
*/
async function main() {
if (
!process.env.OPERATOR_KEY ||
!process.env.OPERATOR_ID ||
!process.env.HEDERA_NETWORK
) {
throw new Error("Please set required keys in .env file.");
}

const operatorId = AccountId.fromString(process.env.OPERATOR_ID);
const operatorKey = PrivateKey.fromStringDer(process.env.OPERATOR_KEY);
const network = process.env.HEDERA_NETWORK;
const client = Client.forName(network).setOperator(operatorId, operatorKey);

// Generate a metadata key
const metadataKey = PrivateKey.generateED25519();
// Generate a supply key
const supplyKey = PrivateKey.generateED25519();
// Initial metadata
const metadata = new Uint8Array([1]);
// New metadata
const newMetadata = new Uint8Array([1, 2]);

let tokenNftsInfo, nftInfo;

try {
// Create a non fungible token
let createTokenTx = new TokenCreateTransaction()
.setTokenName("Test")
.setTokenSymbol("T")
.setTokenType(TokenType.NonFungibleUnique)
.setTreasuryAccountId(operatorId)
.setSupplyKey(supplyKey)
.setMetadataKey(metadataKey)
.freezeWith(client);

// Sign and execute create token transaction
const tokenCreateTxResponse = await (
await createTokenTx.sign(operatorKey)
).execute(client);

// Get receipt for create token transaction
const tokenCreateTxReceipt =
await tokenCreateTxResponse.getReceipt(client);
console.log(
`Status of token create transction: ${tokenCreateTxReceipt.status.toString()}`,
);

// Get token id
const tokenId = tokenCreateTxReceipt.tokenId;
console.log(`Token id: ${tokenId.toString()}`);

// Get token info
const tokenInfo = await new TokenInfoQuery()
.setTokenId(tokenId)
.execute(client);
console.log(`Token metadata key: ${tokenInfo.metadataKey?.toString()}`);

// Mint token
const tokenMintTx = new TokenMintTransaction()
.setMetadata([metadata])
.setTokenId(tokenId)
.freezeWith(client);

const tokenMintTxResponse = await (
await tokenMintTx.sign(supplyKey)
).execute(client);
const tokenMintTxReceipt = await tokenMintTxResponse.getReceipt(client);
console.log(
`Status of token mint transction: ${tokenMintTxReceipt.status.toString()}`,
);

const nftSerial = tokenMintTxReceipt.serials[0];

// Get TokenNftInfo to show the metadata on the NFT created
tokenNftsInfo = await new TokenNftInfoQuery()
.setNftId(new NftId(tokenId, nftSerial))
.execute(client);
nftInfo = tokenNftsInfo[0];
console.log(`Set token NFT metadata:`, nftInfo.metadata);

// Create an account to transfer the NFT to
const accountCreateTx = new AccountCreateTransaction()
.setKey(operatorKey)
.setMaxAutomaticTokenAssociations(10)
.setInitialBalance(new Hbar(100))
.freezeWith(client);

const accountCreateTxResponse = await (
await accountCreateTx.sign(operatorKey)
).execute(client);
const accountCreateTxReceipt =
await accountCreateTxResponse.getReceipt(client);
const newAccountId = accountCreateTxReceipt.accountId;
console.log(`New account id: ${newAccountId.toString()}`);

const tokenAssociateTx = new TokenAssociateTransaction()
.setAccountId(newAccountId)
.setTokenIds([tokenId])
.freezeWith(client);

const tokenAssociateTxResponse = await (
await tokenAssociateTx.sign(operatorKey)
).execute(client);
const tokenAssociateTxReceipt =
await tokenAssociateTxResponse.getReceipt(client);
console.log(
`Status of token associate transaction: ${tokenAssociateTxReceipt.status.toString()}`,
);

// Transfer nft to the new account
const transferNftTx = new TransferTransaction()
.addNftTransfer(tokenId, nftSerial, operatorId, newAccountId)
.freezeWith(client);

const transferNftTxResponse = await (
await transferNftTx.sign(operatorKey)
).execute(client);
const transferNftTxReceipt =
await transferNftTxResponse.getReceipt(client);
console.log(
`Status of transfer NFT transaction: ${transferNftTxReceipt.status.toString()}`,
);

// Update nfts metadata
const tokenUpdateNftsTx = new TokenNftsUpdateTransaction()
.setTokenId(tokenId)
.setSerialNumbers([nftSerial])
.setMetadata(newMetadata)
.freezeWith(client);

const tokenUpdateNftsTxResponse = await (
await tokenUpdateNftsTx.sign(metadataKey)
).execute(client);
const tokenUpdateNftsTxReceipt =
await tokenUpdateNftsTxResponse.getReceipt(client);
console.log(
`Status of token update nfts transction: ${tokenUpdateNftsTxReceipt.status.toString()}`,
);

// Get token nfts info in order to show the metadata on the NFT created
tokenNftsInfo = await new TokenNftInfoQuery()
.setNftId(new NftId(tokenId, nftSerial))
.execute(client);
nftInfo = tokenNftsInfo[0];
console.log(`Updated token NFT metadata:`, nftInfo.metadata);
} catch (error) {
console.log(error);
}

client.close();
}

void main();
Loading
Loading