This package includes all sorts of tooling for the Hedera NFT ecosystem. Some additional features are available only in Node.js e.g: Local token metadata validator.
- Token metadata validator Verify your metadata against the token metadata schema for NFTs, which returns errors and warnings against the standard. You can also define your own token metadata standard and add it to the package to use this schema for validation.
- Local metadata validator - available in Node.js: Verify a local folder containing multiple JSON metadata files against the token metadata schema before publishing the NFT collection on the Hedera network.
- Risk score calculation: Calculate a risk score for an NFT collection from the token information or by passing a token ID of an NFT on the Hedera testnet or mainnet.
- Rarity score calculation: Calculate the rarity scores for a local folder containing multiple JSON metadata files for an NFT collection.
- Trait occurrence calculation: Calculate how often different values for a given trait occur in a collection, percentage-based.
- NFT SDK methods: A wrapper around the Hedera NFT API to create a new NFT collection, mint NFTs, and transfer NFTs.
- Royalty Fee Creator: A factory to define the fees for the Hedera NFT API when creating an NFT collection.
- Metadata Validator: A tool for validating metadata objects according to token metadata schema, providing comprehensive verification of metadata compliance with the selected standard.
- Metadata Builder: Enables the creation and assembly of NFT metadata objects in a structured format and conducts instant validation within its build method, ensuring adherence to token metadata schema prior to deployment.
- Convert CSV To Metadata Objects: Facilitates the conversion of CSV file data into structured metadata objects, streamlining the initial stages of NFT metadata preparation.
- Convert Metadata Objects to JSON Files - available in Node.js: Transforms validated metadata objects into JSON files, ensuring that NFT metadata is properly formatted and stored for deployment.
- Prepare Metadata Objects From CSV Rows: Processes rows of CSV data into ready to validate metadata objects, bridging the gap between raw data collection and NFT metadata standardization.
- Upload Service: Provides tools for uploading files to your chosen file storage service, including:
- uploadFilesFromPath - available in Node.js: Uploads all files from given directory paths or specific files to the configured storage service and returns URLs to the uploaded files.
- uploadBlobFiles: Handles the upload of blob files or buffer files and returns URLs to these files, ensuring that files are not empty before upload.
- handleBlobUpload: Specifically designed for uploading NFT metadata as JSON blobs, generating a URL where the metadata is stored.
- uploadMetadataList: Allows for batch uploading of NFT metadata, handling each metadata item individually and compiling the resulting URLs.
- File Storage Services: Implements various file storage services to handle the storage and retrieval of NFT-related files. This includes:
- AWSService: Uploads files to AWS S3 with public read access and content type handling. It supports multipart uploads and provides error handling for failed uploads.
- PinataService: Utilizes Pinata Cloud to pin files to IPFS, providing an
ipfs://
URL upon successful upload. Includes metadata and options customization. - NftStorageService: Integrates with the NFT.storage API to upload files directly to IPFS and returns an
ipfs://
URL. It supports dynamic API key usage based on a provided list. - MockStorageService: A mock storage service for testing purposes, returning predefined URLs.
- Collection Metadata Validation Provides a possibility to validate the collection metadata of a collection against the HIP-766 metadata schema. This method can handle both direct HTTP(S) URLs or IPFS CIDs as input. If an IPFS CID is provided without a full URL, the method will attempt to use an IPFS gateway to retrieve the metadata. The IPFS gateway parameter is optional; if not specified and required (i.e., when a CID is provided without a full URL), the method will throw an error indicating that the IPFS gateway is required. This ensures that the metadata conforms to the standards required for NFT collections on the Hedera network. The validator provides a thorough check, highlighting any errors or missing fields in the collection metadata structure.
- How to build the package
- Package: Token metadata validator
- Package: Local metadata validator - available in Node.js
- Package: Risk score calculation
- Package: Rarity score calculation
- Package: Trait occurrence calculation
- Package: NFT SDK Methods
- Package: Royalty Fee Creator
- Package: Metadata Validator
- Package: Metadata Builder
- Package: Convert CSV To Metadata Objects
- Package: Convert Metadata Objects to JSON Files - available in Node.js
- Package: Prepare Metadata Objects From CSV Rows
- Package: Upload Service - with Node.js features
- Package: File Storage Services
- Package: Collection Metadata Validation
- Questions, contact us, or improvement proposals?
- Support
- Contributing
- Code of Conduct
- License
To build this package, run the below command:
npm run build
This command will produce a dist
folder containing the outputted JavaScript files.
Verify your metadata against the token metadata schema for NFTs which returns errors and warnings against the standard.
Install the package:
npm i -s @hashgraph/hedera-nft-sdk
Import the package into your project. You can import the Validator
class and the default schema version for token metadata with defaultSchemaVersion
.
const { Validator, defaultSchemaVersion } = require('@hashgraph/hedera-nft-sdk');
You can use the Validator
like below.
- The first parameter is the JSON object you want to verify against a JSON schema
- The second parameter is the version of the token metadata schema against which you want to validate your metadata instance. The default value is
2.0.0
(V2). In the future, new functionality might be added, releasing new version numbers.
const metadata = {
attributes: [{ trait_type: 'Background', value: 'Yellow' }],
creator: 'NFT artist',
};
const version = '2.0.0';
const validator = new Validator();
const issues = validator.validate(metadata, version);
The output interface for issues contains errors
and warnings
.
{
"errors": [
{
"type": "Indicates which validator created the error. Possible values: schema, attribute, localization, and SHA256.",
"msg": "Indicates the specific error explanation to be displayed to the user",
"path": "Indicates the path of the property for which the error is returned"
}
],
"warnings": [
{
"type": "schema",
"msg": "is not allowed to have the additional property 'someAdditionalProperty'",
"path": "Indicates the path of the property for which the error is returned"
}
]
}
Here's an example:
{
"errors": [
{
"type": "attribute",
"msg": "Trait stamina of type 'percentage' must be between [0-100], found 157",
"path": "instance.attributes[0]"
}
],
"warnings": [
{
"type": "schema",
"msg": "is not allowed to have the additional property 'imagePreview'",
"path": "instance"
}
]
}
See: /examples/token-metadata-validator
The easiest approach to adding new schemas is using the constructor of the Validator
class. It accepts an array of JSON objects, each containing a JSON schema and tag for the schema. The tag is used to refer to the schema when validating metadata instances.
Therefore, each tag needs to be unqiue. The following tags can't be used as they are already occupied:
1.0.0
-> Refers to token metadata JSON schema V1 (HIP10)2.0.0
-> Refers to token metadata JSON schema V2 (HIP412), which is the latest schema
You can add your custom schema like this:
const { Validator } = require('@hashgraph/hedera-nft-sdk');
// Define your schema
const customSchema = {
title: 'Token Metadata',
type: 'object',
additionalProperties: false,
properties: {
name: {
type: 'string',
description: 'Identifies the asset to which this token represents.',
},
},
required: ['name'],
};
// Create Validator instance with custom schema labeled "custom-v1"
const validator = new Validator([{ schemaObject: customSchema, tag: 'custom-v1' }]);
// Verify metadata against custom schema
const results = validator.validate(metadataInstance, 'custom-v1');
console.log(results);
Examples: See: /examples/token-metadata-calculation
⚠️ Warning: This approach requires you to rebuild the package.
You can add custom JSON schemas to the /schemas
folder.
You can then add the version to the schemaMap
in /schema/index.js
using the following code:
const token_metadata_2_0_0 = require('./[email protected]');
const myCustomSchema = require('./myschema.json'); // import your schema
const schemaMap = new Map();
schemaMap.set('2.0.0', token_metadata_2_0_0);
schemaMap.set('<version>', myCustomSchema); // Add your schema to the map
When you've added your schema to the map, you can validate against your schema version by passing your version to the validator()
function.
Set custom validation rules by importing new validators from the /validators
folder into the index.js
file. You can then add them to the validate()
function. Stick to the issues
format of errors and warnings (see section "Issues format" for the detailed description).
const { myCustomValidator, schemaValidator } = require('./validators');
const validate = (instance, schemaVersion = defaultSchemaVersion) => {
let errors = [];
let warnings = [];
const schema = this.getSchema(schemaVersion);
// When errors against the schema are found, you don't want to continue verifying the NFT
// Warnings don't matter because they only contain "additional property" warnings that don't break the other validators
const schemaProblems = schemaValidator(instance, schema);
warnings.push(...schemaProblems.warnings);
if (schemaProblems.errors.length > 0) {
errors.push(...schemaProblems.errors);
return {
errors,
warnings,
};
}
const customErrors = myCustomValidator(instance);
errors.push(...customErrors);
return {
errors,
warnings,
};
};
Verify a local folder containing multiple JSON metadata files against the token metadata schema before publishing the NFT collection on the Hedera network.
Install the package:
npm i -s @hashgraph/hedera-nft-sdk
Import the package into your project and get the localValidation
function.
const { localValidation } = require('@hashgraph/hedera-nft-sdk');
The localValidation
expects a relative path to your metadata files to verify them. The function prints the warnings and errors for all JSON files it finds in the provided folder path. It also returns the validation results as an object in case you want to use the results in your code.
const relativePathToFiles = './examples/local-metadata-validator/files';
const issues = localValidation(relativePathToFiles);
This package uses the Validator
class explained in the previous section.
The output interface for this function looks like this.
{
"filename.json": {
"errors": [
{
"type": "Indicates which validator created the error. Possible values: schema, attribute, localization, and SHA256.",
"msg": "Indicates the specific error explanation to be displayed to the user",
"path": "Indicates the path of the property for which the error is returned"
}
],
"warnings": [
{
"type": "schema",
"msg": "is not allowed to have the additional property 'someAdditionalProperty'",
"path": "Indicates the path of the property for which the error is returned"
}
]
},
"filename2.json": ...
}
See: /examples/local-metadata-validator/index.js
Calculate risk score for a token from the token information or by passing a token ID of an NFT on the Hedera testnet or mainnet.
The total risk score is calculated based on the presence of certain keys
for the token or the presence of an INFINITE
supply_type
in combination with a supply_key
. Each key or property has an associated weight.
const defaultWeights = {
keys: {
admin_key: 200,
wipe_key: 200,
freeze_key: 50,
supply_key: 20,
kyc_key: 50,
pause_key: 50,
fee_schedule_key: 40,
metadata_key: 200,
},
properties: {
supply_type_infinite: 20,
},
};
However, there's one edge case where the 20 weight for the supply key is not counted. When the supply type is set to FINITE
and the total supply equals the max supply, there's no risk the supply key can further dilute the project because the project's minting limit has been reached.
To determine the risk level, there are four categories each with an attached score. If the score is lower than or equal to a risk level, it will get that risk level. E.g. a token with a risk score of 200 will get a HIGH
risk level.
const defaultRiskLevels = {
NORISK: 0,
LOW: 40,
MEDIUM: 199,
HIGH: 200,
};
Install the package:
npm i -s @hashgraph/hedera-nft-sdk
Import the package into your project and get the calculateRiskScoreFromData
or calculateRiskScoreFromTokenId
functions.
const { calculateRiskScoreFromData, calculateRiskScoreFromTokenId } = require('@hashgraph/hedera-nft-sdk');
The calculateRiskScoreFromData
expects a token information JSON object as returned by the /api/v1/tokens/ endpoint (here's an example of token data).
const tokenInformation = {
"admin_key": null,
"auto_renew_account": "0.0.784037", "auto_renew_period": 7776000,
"freeze_key": null,
...
}
const results = calculateRiskScoreFromData({ metadata: tokenInformation });
Alternatively, use the calculateRiskScoreFromTokenId
to retrieve risk information about a token by entering a token ID. This asynchronous function looks up the token information from the mirror node and returns the risk information.
const results = await calculateRiskScoreFromTokenId({ tokenId: '0.0.1270555' });
Use custom weights and risk levels by passing them as the second and third parameter to the calculateRiskScoreFromData
function.
const metadata: Metadata = {
supply_type: 'testSupply',
supply_key: 'testKey',
max_supply: 'testMaxSupply',
total_supply: 'testTotalSupply',
};
const customWeights: Weights = {
keys: {
admin_key: 200,
wipe_key: 200,
freeze_key: 50,
supply_key: 20,
kyc_key: 50,
pause_key: 50,
fee_schedule_key: 40,
metadata_key: 200,
},
properties: {
supply_type_infinite: 20,
},
};
const customRiskLevels: RiskLevels = {
NORISK: 0,
LOW: 40,
MEDIUM: 199,
HIGH: 200,
};
const results = calculateRiskScoreFromData({ metadata, customWeights, customRiskLevels });
The output interface for this function looks like this.
{
"riskScore": "number representing total risk score",
"riskLevel": "<string: ENUM(NO RISK, LOW, MEDIUM, HIGH)>"
}
See: /examples/risk-score-calculation
Calculate the rarity for a local folder containing multiple JSON metadata files for an NFT collection. This package uses the trait normalization rarity scoring model because it's the fairest model to calculate rarity. The model works by dividing the number one by the division of the number of NFTs with a specific trait value and the number of NFTs with the most common trait value for that trait. Here's the formula:
1 / (# of NFTs with trait value / # of NFTs with most common trait value)
This model outputs a score for each NFT. By sorting the NFTs, you'll get a ranking based on this scoring model.
Install the package:
npm i -s @hashgraph/hedera-nft-sdk
Import the package into your project and get calculateRarity
function. Next, you need to pass an array of your metadata files:
[
{
fileName: '1.json',
file: new Blob[JSON.stringify("{ name: 'Nft name', ...} "), { type: 'application/json'}]
}
]
const { calculateRarity } = require('@hashgraph/hedera-nft-sdk');
const metadataFiles = [
{
fileName: '1.json',
file: new Blob[JSON.stringify("{ name: 'Nft name', ...}"), { type: 'application/json' }]
}
]
const results = await calculateRarity(metadataFiles);
console.log(results);
You can also avoid having to load data with Blob interface and instead use calculateRarityFromData
function.
const NFTdata = [
{
name: 'HANGRY BARBOON #2343',
image: 'ipfs://QmaHVnnp7qAmGADa3tQfWVNxxZDRmTL5r6jKrAo16mSd5y/2343.png',
type: 'image/png',
attributes: [
{ trait_type: 'Background', value: 'Yellow' },
{ trait_type: 'Fur', value: 'Silver' },
{ trait_type: 'Clothing', value: 'Herbal Jacket' },
{ trait_type: 'Mouth', value: 'Smile' },
{ trait_type: 'Sing', value: 'Sing' },
],
},
];
const results = calculateRarityFromData(NFTdata);
According to token metadata schema, the calculateRarity
function only looks at objects in the attributes
property that use the following format:
{ "trait_type": "Background", "value": "Yellow" }
It does not take into account attributes with the display_type
property set, like this:
{ "trait_type": "Background", "value": 10, "display_type": "percentage" }
The output interface for this function looks like this.
[
{ "rarity": "<string> rarity score", "NFT": "<nubmer> NFT number", "filename": "<string optional>" },
...
]
Here's a sample output. The total sum of the individual attributes is always 100%.
[
{
"attributeContributions": [
{
"trait": "Background",
"value": "Yellow",
"contribution": "18.18"
},
{
"trait": "Fur",
"value": "Gold",
"contribution": "18.18"
},
{
"trait": "Clothing",
"value": "Floral Jacket",
"contribution": "18.18"
},
{
"trait": "Mouth",
"value": "Tongue",
"contribution": "27.27"
},
{
"trait": "Sing",
"value": "None",
"contribution": "18.18"
}
],
"totalRarity": "5.50",
"NFT": 1,
"filename": "nft1.json"
},
...
]
See:
Calculate how often different values for a given trait occur in a collection, percentage-based.
Install the package:
npm i -s @hashgraph/hedera-nft-sdk
Import the package into your project and get calculateTraitOccurrenceFromData
function. Next, you need to pass a JSON array containing NFT collection metadata to the function.
const NFTdata = [
{
"creator": "HANGRY BARBOONS",
"description": "HANGRY BARBOONS are 4,444 unique citizens from the United Hashgraph of Planet Earth. Designed and illustrated by President HANGRY.",
"format": "none",
"name": "HANGRY BARBOON #2343",
"image": "ipfs://QmaHVnnp7qAmGADa3tQfWVNxxZDRmTL5r6jKrAo16mSd5y/2343.png",
"type": "image/png",
"properties": { "edition": 2343 },
"attributes": [
{ "trait_type": "Background", "value": "Yellow" },
{ "trait_type": "Mouth", "value": "Nose" }
]
},
...
]
const results = calculateTraitOccurrenceFromData(NFTdata);
The output interface for this function looks like this.
[
{
"trait": "<string> trait name",
"values": [
{
"value": "<string> single value for trait",
"occurrence": "<string> percentage based occurrence with 2 digits after comma"
},
...
]
},
...
]
Here's a sample output that shows the percentage of each value's occurrence for a given trait.
[
{
"trait": "Background",
"values": [
{
"value": "Yellow",
"occurence": "60.00"
},
{
"value": "Green",
"occurence": "40.00"
}
]
},
{
"trait": "Mouth",
"values": [
{
"value": "Nose",
"occurence": "20.00"
},
{
"value": "Tongue",
"occurence": "20.00"
},
{
"value": "Smile",
"occurence": "60.00"
}
]
}
]
See:
Each of HederaNFTSDK function are methods in class HederaNFTSDK
which is a wrapper around the native Hedera SDK. The class is used to create a new NFT collection, mint NFTs, and transfer NFTs.
Install the package:
npm i -s @hashgraph/hedera-nft-sdk
Create new instance of HederaNFTSDK
class by passing the operator account ID, operator private key, and network to the constructor.
HederaNFTSDK class has login function in constructor which logs in the operator account and sets the operator account ID and operator private key.
You should create this instance only once. Every exported function will be automatically logged in with the operator account.
new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
Create new instance of HederaNFTSDK
in the following parameters:
type HederaNFTSDKType = {
accountId: string;
privateKey: PrivateKey;
network: Network;
localNode?: LocalNode;
localMirrorNode?: string;
mirrorNodeUrl?: string;
};
accountId
: The account ID of the operator account.privateKey
: The private key of the operator account.network
: The network to use (mainnet, testnet, previewnet or loocalNode).localNode
: The local node to use.localMirrorNode
: The local mirror node to use.mirrorNodeUrl
: The mirror node URL to use.
The create-collection
method is used to create a new NFT collection. This method takes in a collection name and collection symbol and returns a promise that resolves when the collection is successfully created.
Create instance of HederaNFTSDK
class and call createCollection
method by passing proper parameters.
const HederaNFTSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
const tokenId = await HederaNFTSDK.createCollection({
collectionName: 'test_name',
collectionSymbol: 'test_symbol',
});
Create collection method takes in the following parameters:
type CreateCollectionType = {
collectionName: string;
collectionSymbol: string;
treasuryAccountPrivateKey?: PrivateKey;
treasuryAccount?: string;
keys?: CreateCollectionKeysType;
maxSupply?: number;
customFees?: CustomFeeType[];
expirationTime?: Date;
autoRenewAccount?: string;
autoRenewAccountPrivateKey?: PrivateKey;
autoRenewPeriod?: number;
memo?: string;
};
collectionName
: The name of the NFT collection.collectionSymbol
: The symbol of the NFT collection.treasuryAccountPrivateKey
: The private key of the treasury account. If not provided, the operator account will be used.treasuryAccount
: The treasury account ID. If not provided, the operator account will be used.keys
: The keys for the collection.maxSupply
: The maximum supply of the collection.customFees
: The custom fees for the collection.expirationTime
: The expiration time of the collection.autoRenewAccount
: The auto-renew account for the collection.autoRenewAccountPrivateKey
: The private key of the auto-renew account.autoRenewPeriod
: The auto-renew period for the collection.memo
: The memo for the collection.
Method return string which is the token ID of the newly created NFT collection.
See: /examples/local-metadata-validator/index.js
The estimateCreateCollectionInDollars
method is used to estimate the cost of creating a new NFT collection. This method takes in a collection name and collection symbol and returns a promise that resolves when the cost is successfully estimated.
Create instance of HederaNFTSDK
class and call estimateCreateCollectionInDollars
method by passing the proper parameters.
const HederaNFTSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
const estimatedDollars = estimateCreateCollectionInDollars({
collectionName: 'test',
collectionSymbol: 'test2',
});
Estimate create collection in dollars method takes in the following parameters:
type EstimateCreateCollectionInDollarsType = {
collectionName: string;
collectionSymbol: string;
treasuryAccountPrivateKey?: PrivateKey;
treasuryAccount?: string;
keys?: CreateCollectionKeysType;
customFees?: CustomFeeType[];
};
collectionName
: The name of the NFT collection.collectionSymbol
: The symbol of the NFT collection.treasuryAccountPrivateKey
: The private key of the treasury account. If not provided, the operator account will be used.treasuryAccount
: The treasury account ID. If not provided, the operator account will be used.keys
: The keys for the collection.customFees
: The custom fees for the collection.
Method return number which is the estimated cost of creating a new NFT collection in dollars.
See: /examples/local-metadata-validator/index.js
The estimateCreateCollectionInHbar
method is used to estimate the cost of creating a new NFT collection. This method takes in a collection name and collection symbol and returns a promise that resolves when the cost is successfully estimated.
Create instance of HederaNFTSDK
class and call estimateCreateCollectionInHbar
method by passing the proper parameters.
const HederaNFTSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
const estimatedDollars = estimateCreateCollectionInHbar({
collectionName: 'test',
collectionSymbol: 'test2',
});
Estimate create collection in hbar method takes in the following parameters:
type EstimateCreateCollectionInDollarsType = {
collectionName: string;
collectionSymbol: string;
treasuryAccountPrivateKey?: PrivateKey;
treasuryAccount?: string;
keys?: CreateCollectionKeysType;
customFees?: CustomFeeType[];
};
collectionName
: The name of the NFT collection.collectionSymbol
: The symbol of the NFT collection.treasuryAccountPrivateKey
: The private key of the treasury account. If not provided, the operator account will be used.treasuryAccount
: The treasury account ID. If not provided, the operator account will be used.keys
: The keys for the collection.customFees
: The custom fees for the collection.
Method return number which is the estimated cost of creating a new NFT collection in hbars.
The mintSharedMetadata
method is used to mint NFTs with shared metadata. This method takes in a tokenId, supplyKey, amount, and metadata object, and returns a promise that resolves when the NFTs are successfully minted.
This function supports bulk minting. The number of NFTs minted is determined by the amount parameter.
Create instance of HederaNFTSDK
class and call mintSharedMetadata
method by passing the proper parameters.
const HederaNFTSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
const mintedMetadata = await HederaNFTSDK.mintSharedMetadata({
tokenId,
amount,
metaData: 'ipfs://bafkreiaghprbybrlrpvjvzqurwmjgfgxp6beo6jhwfarte76qra2xcei3u',
batchSize: 2,
supplyKey,
});
Mint shared metadata method takes in the following parameters:
type MintSharedType = {
tokenId: string;
amount: number;
metaData: string;
batchSize?: number;
supplyKey?: string;
};
tokenId
: The token ID of the NFT collection.amount
: The amount of NFTs to mint.metaData
: The metadata of the NFTs.batchSize
: The amount of NFTs minted in a single on-chain transaction (defaults to 5).supplyKey
: The supply key of the NFTs.
Method returns an array of objects containing the token ID and the serial number of the minted NFTs.
type MintedNFTType = { serialNumber: number; content: string };
The mintUniqueMetadata
method is used to mint NFTs with unique metadata. This method takes in a tokenId, supplyKey, and an array of NFT metadata or path to metadata object file and returns a promise that resolves when the NFTs are successfully minted.
This function supports bulk minting. The number of NFTs minted is determined by the length of metadata array, just as in regular SDK, but it's not limited to 10 elements.
Create instance of HederaNFTSDK
class and call mintUniqueMetadata
method by passing the proper parameters.
const HederaNFTSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
// Pass the metadata as an array
const mintedMetadata = await HederaNFTSDK.mintUniqueMetadata({
tokenId,
supplyKey,
batchSize: 2,
metadata: [
'ipfs://bafkreiaghprbybrlrpvjvzqurwmjgfgxp6beo6jhwfarte76qra2xcei3u',
'ipfs://bafkreibqfchoan4gt4qz34ztfmrzo7lksf465ihb6czofz4t2z4dmbxnc4',
],
});
// Pass the path to the metadata file
const mintedMetadata = await HederaNFTSDK.mintUniqueMetadata({
tokenId,
supplyKey,
batchSize: 2,
pathToMetadataURIsFile: pathToOneLineCSV,
});
Mint unique metadata method takes in the following parameters:
type MintUniqueType = {
tokenId: string;
supplyKey: string;
batchSize?: number;
pathToMetadataURIsFile?: string;
metadata?: string[];
};
tokenId
: The token ID of the NFT collection.supplyKey
: The supply key of the NFTs.batchSize
: The amount of NFTs minted in a single on-chain transaction (defaults to 5).pathToMetadataURIsFile
: The path to the file containing the metadata URIs.metadata
: The metadata URIs of the NFTs.
Method returns an array of objects containing the token ID and the serial number of the minted NFTs.
type MintedNFTType = { serialNumber: number; content: string };
The estimateNftMintingInDollars
method is used to estimate the cost of minting NFTs. This method takes in a nft amount and returns a promise that resolves when the cost is successfully estimated.
Create instance of HederaNFTSDK
class and call estimateNftMintingInDollars
method by passing the proper parameters.
const HederaNFTSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
const nfts = ['1', '2', '3', '4', '5'];
const result = await HederaNFTSDK.estimateNftMintingInDollars({ amountOfNfts: nfts.length });
Estimate mint metadata in dollars method takes in the following parameters:
type EstimateMintDollarsType = {
amountOfNfts: number;
};
amountOfNfts
: The amount of NFTs to mint.
Method return number which is the estimated cost of minting NFTs in dollars.
The estimateNftMintingInHbar
method is used to estimate the cost of minting NFTs. This method takes in a nft amount and returns a promise that resolves when the cost is successfully estimated.
Create instance of HederaNFTSDK
class and call estimateNftMintingInHbar
method by passing the proper parameters.
const HederaNFTSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
const nfts = ['1', '2', '3', '4', '5'];
const result = await HederaNFTSDK.estimateNftMintingInHbar({ amountOfNfts: nfts.length });
Estimate mint metadata in hbar method takes in the following parameters:
type EstimateMintHbarType = {
amountOfNfts: number;
};
amountOfNfts
: The amount of NFTs to mint.
Method return number which is the estimated cost of minting NFTs in hbar.
The increaseNFTSupply
method is used to increase the supply of NFTs.
Create instance of HederaNFTSDK
class and call increaseNFTSupply
method by passing the proper parameters.
const HederaNFTSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');
const increaseSupplyResult = await HederaNFTSDK.increaseNFTSupply({
nftId: nft.nftId,
amount: 5,
batchSize: 10,
supplyKey,
});
Increase NFT supply method takes in the following parameters:
type IncreaseNFTSupplyType = {
nftId: NftId;
amount: number;
batchSize?: number;
supplyKey?: string;
};
nftId
: The ID of the NFT.amount
: The amount of NFTs to mint.batchSize
: The amount of NFTs minted in a single on-chain transaction (defaults to 5).supplyKey
: The supply key of the NFTs.
Method returns an array of objects containing the token ID and the serial number of the minted NFTs.
type MintedNFTType = { serialNumber: number; content: string };
The getHolderAndDuration
method is used to get the holder and duration of an NFT. This method runs without instance of HederaNFTSDK
class.
Call getHolderAndDuration
method by passing the proper parameters.
const result = await getHolderAndDuration({ tokenId, serialNumber: nftSerial, network: 'testnet' });
Create royalty fee method takes in the following parameters:
type GetHolderAndDurationType = {
tokenId: string;
serialNumber: number;
network?: NetworkName;
};
tokenId
: The token ID of the NFT.serialNumber
: The serial number of the NFT.network
: The network to use (mainnet, testnet, previewnet or loocalNode).
Method returns an object containing the holder and duration of the NFT.
type HolderAndDurationType = { holder: string; duration: number };
The FeeFactory
class is used to create custom fees for NFT collections. The class is used to create fixedFee or royaltyFee.
Initialize the class and use one of the methods to create a fee.
Install the package:
npm i -s @hashgraph/hedera-nft-sdk
Create new instance of FeeFactory
feeFactoryInstance = new FeeFactory();
The fixedFee
method is used to create a fixed fee for NFT collections.
Create new instance of FeeFactory
const feeFactoryInstance = new FeeFactory();
Call fixedFee
method by passing the proper parameters.
const fixedFee = feeFactoryInstance.fixedFee({
allCollectorsAreExempt: false,
collectorAccountId: myAccountId,
hbarAmount: 100,
});
Create fixed fee method takes in the following parameters(You need to pass either hbarAmount or (amount and denominatingTokenId)):
type FixedFeeType = {
collectorAccountId: string;
hbarAmount?: number;
amount?: number;
denominatingTokenId?: string;
allCollectorsAreExempt?: boolean;
};
collectorAccountId
: The account ID of the collector.hbarAmount
: The amount of hbar to charge.amount
: The amount to charge.denominatingTokenId
: The token ID to use for the fee.allCollectorsAreExempt
: Whether all collectors are exempt from the fee.
The royaltyFee
method is used to create a royalty fee for NFT collections.
Create new instance of FeeFactory
const feeFactoryInstance = new FeeFactory();
Call fixedFee
method by passing the proper parameters.
const fixedFee = feeFactoryInstance.fixedFee({
allCollectorsAreExempt: false,
collectorAccountId: myAccountId,
hbarAmount: 100,
});
Create royalty fee method takes in the following parameters:
type RoyaltyFeeType = {
collectorAccountId: string;
numerator: number;
denominator: number;
fallbackFee?: FixedFeeType;
allCollectorsAreExempt?: boolean;
};
collectorAccountId
: The account ID of the collector.numerator
: The numerator of the royalty fee.denominator
: The denominator of the royalty fee.fallbackFee
: The fallback fee for the royalty fee.allCollectorsAreExempt
: Whether all collectors are exempt from the fee.
The TokenMetadataValidator
class is a comprehensive tool designed to facilitate the validation of NFT metadata against the token metadata schema. This class provides developers with a suite of methods to validate individual NFT metadata objects, arrays of metadata, local files, and directories containing NFT metadata, ensuring compliance with the token metadata schema. Additionally, it offers functionalities to validate metadata directly from the Hedera network, providing a robust solution for ensuring the integrity and compliance of NFT metadata within the Hedera ecosystem.
The class methods can be directly invoked to perform metadata validation.
validateSingleMetadataObject
- Validates a single NFT metadata object against the token metadata schema.
const validationResult = TokenMetadataValidator.validateSingleMetadataObject(metadataObject);
This method returns an object contains:
isValid
boolean flag- Array of errors
type validationResult = {
isValid: boolean;
errors: string[];
};
validateArrayOfObjects
- Takes an array of metadata objects and validates each one against the token metadata schema, providing detailed results for each object.
const validationResults = TokenMetadataValidator.validateArrayOfObjects(arrayOfMetadataObjects);
This method returns an object contains:
isValid
: A boolean flag indicating whether the metadata object at the index passed validation,
errors
: An array of strings listing all validation errors found for the metadata object,
errorsCount
: The number of errors found for the metadata object,
allObjectsValid
: A boolean flag indicating whether all metadata objects in the array passed validation without any errors.
type validationResult = {
allObjectsValid: boolean;
results: {
[index: number]: {
isValid: boolean;
errorsCount: number;
errors: string[];
};
};
};
validateLocalFile
- This method allows for the validation of metadata within a local file. It reads the file content, parses the JSON, and validates it against the token metadata schema.
const pathToFile = 'path/to/your/file';
const fileValidationResult = TokenMetadataValidator.validateLocalFile(pathToFile);
This method returns an object contains:
isValid
boolean flag- Array of errors
type validationResult = {
isValid: boolean;
errors: string[];
};
validateLocalDirectory
- Validates all JSON metadata files within a specified directory, offering a comprehensive tool for pre-publish validation of NFT collections.
const directoryPath = 'path/to/your/metadata/directory';
const directoryValidationResult = TokenMetadataValidator.validateLocalDirectory(directoryPath);
This method returns an object contains:
isValid
: A boolean flag indicating whether all files within the specified directory passed validation. It is true if all files are valid according to the token metadata schema, and false otherwise.errors
: An array of objects, each corresponding to a file that failed validation. Each object include:fileName
: The name of the file that encountered validation errors, helping to identify the source of the issue.general
: An array of strings, with each string describing a specific validation error encountered in the file.
type validationResult = {
isValid: boolean;
errors: string[];
};
validateSingleOnChainNFTMetadata
- Targets the validation of metadata for a single NFT within a collection on the Hedera network. This method is particularly useful for in-depth analysis of individual NFTs.
type validateSingleOnChainNFTMetadataType = {
network: string;
tokenId: string;
serialNumber: string;
ipfsGateway?: string;
};
const singleNftValidationResult = await TokenMetadataValidator.validateSingleOnChainNFTMetadata(
network,
tokenId,
serialNumber,
ipfsGateway
);
network
: The network to use (mainnet, testnet or previewnet),tokenId
: The unique identifier of the NFT token within the Hedera network, used to locate and validate metadata for the specific token,serialNumber
: The serial number of the NFT, allowing for the validation of metadata for individual NFTs within a collection,ipfsGateway
: Optional. Specifies the IPFS gateway URL to be used for decoding the encoded NFT metadata URL.
This method returns an object contains:
isValid
boolean flag- Array of errors
type validationResult = {
isValid: boolean;
errors: string[];
};
validateMetadataFromOnChainCollection
- Fetches and validates metadata for an entire NFT collection directly from the Hedera network, leveraging either the testnet or mainnet. This method is crucial for verifying the compliance of on-chain NFT collections.
type validateSingleOnChainNFTMetadataType = {
network: string;
tokenId: string;
ipfsGateway?: string;
limit: number;
};
const collectionValidationResult = await TokenMetadataValidator.validateMetadataFromOnChainCollection(network, tokenId, ipfsGateway, limit);
network
: The network to use (mainnet, testnet or previewnet),tokenId
: The unique identifier of the NFT token within the Hedera network, used to locate and validate metadata for the specific token,ipfsGateway
: Optional. Specifies the IPFS gateway URL to be used for decoding the encoded NFT metadata URL,limit
: Specifies how many NFT per page should be fetched. Default number is set to 100.
This method returns an object containing:
isValid
: A boolean flag indicating whether all metadata objects passed validation without any errors.errors
: An array of objects, each containing aserialNumber
identifying the specific NFT and amessage array
listing all validation errors found for that NFT.
type validationResult = {
isValid: boolean;
errors: string[];
};
The Hip412MetadataBuilder
class streamlines the creation of NFT metadata objects in alignment with the token metadata schema. It provides a fluent interface to incrementally build up a metadata object with validation at each step, ensuring that the resulting metadata conforms to the required specifications. This builder class is essential for developers seeking to craft compliant NFT metadata for deployment on the Hedera network.
Upon instantiation, the Hip412MetadataBuilder
initializes a metadata object with name
, image
and type
empty fields. Users can then sequentially apply various setters and adders to populate this metadata object with the necessary details.
const metadataBuilder = new Hip412MetadataBuilder();
- setName(name: string): 'Sets the name of the NFT', // required
- setImage(image: string): 'Sets the image URL for the NFT', // required
- setType(type: string): 'Sets the type of the NFT', // required
- setDescription(description: string): 'Adds a description to the NFT metadata',
- setCreator(creator: string): 'Defines the creator of the NFT',
- setCreatorDID(creatorDID: string): 'Specifies the Decentralized Identifier (DID) for the creator',
- setChecksum(checksum: string): 'Assigns a checksum for the metadata integrity verification',
- addAttribute(attribute: Attribute): 'Appends a custom attribute to the NFT', //can be used multiple times
- addFile(file: FileMetadata): 'Adds a file (with URI, type, etc.) to the NFT metadata', // can be used multiple times
- addProperty({ key, value }): 'Includes a custom property to the NFT metadata', // can be used multiple times
- setLocalization(localization: Localization): 'Establishes localization information for the NFT metadata',
- build(): 'Validates and finalizes the metadata object, returning both the metadata and its validation result'. // required
Here's an example of how to use the Hip412MetadataBuilder
to construct NFT metadata:
const { metadata, validationResult } = new Hip412MetadataBuilder()
.setName('My Awesome NFT')
.setImage('https://example.com/my-awesome-nft.png')
.setType('image/png')
.setDescription('This is a description of my awesome NFT')
.addAttribute({
trait_type: 'Background',
value: 'Space',
})
.addFile({
uri: 'https://example.com/nft-metadata.json',
type: 'application/json',
})
.build();
The build
method returns an object containing:
-
metadata
: This property holds the constructed metadata object that has been assembled using the builder methods. The metadata object follows the structure required by token metadata schema, including attributes such as name, image, type, and any additional attributes or files that were added. This object is ready to be used for NFT creation or further processing. -
validationResult
: This property contains the results of validating the constructed metadata object against the token metadata schema. It provides feedback on the compliance of the metadata, including a boolean flag indicating validity (isValid) and detailed error information (as array of strings) for each metadata element that was evaluated.
{
"name": "My Awesome NFT",
"image": "https://example.com/my-awesome-nft.png",
"type": "image/png",
"description": "This is a description of my awesome NFT",
"attributes": [
{
"trait_type": "Background",
"value": "Space"
}
],
"files": [
{
"uri": "https://example.com/nft-metadata.json",
"type": "application/json"
}
],
"format": "[email protected]" // Automatically added by the builder to indicate compliance with a specific version of the standard
}
type validationResult = {
isValid: boolean;
errors: string[];
};
The convertCSVToMetadataObjects
function is designed to transform CSV files into an array of metadata objects compliant with the NFT metadata structure defined in the token metadata schema. This utility function facilitates the conversion of bulk NFT data stored in CSV format into a structured JSON format that can be directly utilized for NFT minting or further processing within the NFT ecosystem.
To convert a CSV file into an array of metadata objects, you need to provide the CSV file. Optionally, you can also specify a limit to control the number of rows processed from the CSV file.
function convertCSV(csvFile: File) {
const metadataObjects = await convertCSVToMetadataObjects(csvFile, 100);
}
// or
const csvBlob = new Blob(['csv string'], { type: 'text/csv' })
const metadataObjects = await convertCSVToMetadataObjects(csvBlob, 100);
csvFile
: instance that fulfils Blob interface,limit
: An optional parameter that defines the maximum number of rows to be processed from the CSV file. If not provided, all rows in the file will be processed.
Important! The first two lines in the csv file are headers and they are skipped. You can find a valid csv example at the path src/test/__mocks__/csv/csv-example-with-all-fields
This function returns a promise that resolves to an array of MetadataObjects. Each MetadataObject
in the array represents an individual NFT's metadata, structured according to the requirements of the token metadata schema.
If the CSV file contains fewer data rows than the headers (after omitting specific header counts defined in the SDK), an error is thrown, indicating that the CSV file is empty or does not contain sufficient data for processing.
The convertMetadataObjectsToJsonFiles
function streamlines the process of converting an array of NFT metadata objects into individual JSON files. This utility is particularly useful for batch processing and storage of NFT metadata, facilitating easy upload and management of NFT collections. Before conversion, it validates each metadata object against the token metadata schema to ensure compliance.
To convert metadata objects into JSON files, you need to provide the array of metadata objects, the destination path for the saved JSON files, and optionally, a limit to control the number of metadata objects processed.
const metadataObjects = [
{
/* Your Metadata Objects */
},
];
const savedJsonFilesLocation = 'path/to/save/json-files';
const limit = 100; // Optional
const conversionResult = await convertMetadataObjectsToJsonFiles({
metadataObjects,
savedJsonFilesLocation,
limit,
});
metadataObjects
: An array of MetadataObject items to be converted into JSON files. EachMetadataObject
should conform to the structure required by the NFT metadata schema,savedJsonFilesLocation
: A string specifying the directory path where the resulting JSON files should be saved,limit
: An optional parameter specifying the maximum number of metadata objects to process. If not provided, all objects in themetadataObjects
array will be processed.
This function returns a promise that resolves to an object with the following properties:
isValid
: A boolean flag indicating whether all provided metadata objects are valid according to the token metadata validation process,errors
: An array containing detailed error information for each metadata object that failed validation. Each error object includes the index of the metadata object (objectIndex) and an array of error messages (errors),savedJsonFilesLocation
: The location where the JSON files have been saved.
The convertMetadataObjectsToJsonFiles
function strictly requires all metadata objects to pass token metadata validation before proceeding with the conversion to JSON files. The validation is performed upfront, and only if every metadata object is deemed valid, will the function save the JSON files to the specified location. If any of the metadata objects fail validation, no files will be saved, and the function will return detailed information about the errors encountered. This ensures the integrity and compliance of all NFT metadata before it is serialized into JSON format, allowing developers to rectify any issues in a single batch process.
The prepareMetadataObjectsFromCSVRows
function serves as an intermediary step in the conversion of CSV data into structured NFT metadata objects. It processes rows of CSV data, applying a predefined schema to transform them into an array of metadata objects suitable for NFT creation or further validation against the token metadata schema.
To transform CSV rows into metadata objects, you need to provide the parsed rows from a CSV file. The function utilizes predefined headers for attributes and properties to map CSV data accurately into metadata objects.
const csvParsedRows = [
{
/* Array of parsed CSV rows */
},
];
const metadataObjects = prepareMetadataObjectsFromCSVRows({ csvParsedRows });
csvParsedRows
: An array of CSVRow objects, representing the rows parsed from a CSV file. Each CSVRow object is a key-value map corresponding to one row of data in the CSV, where keys are column headers, and values are the cell data for that row.
The function returns an array of metadata objects, with each object structured according to the NFT metadata schema. This array can be directly used for NFT minting, further validation, or conversion into JSON files for storage and distribution.
The function relies on predefined headers for attributes (ATTRIBUTES) and properties (PROPERTIES) to map data from CSV rows into the structured format required by NFT metadata. This ensures that the resulting metadata objects are correctly formatted and include all necessary information for NFT creation, such as names, images, types, and other customizable attributes and properties.
The Upload Service class is a versatile component of the SDK that facilitates the upload of files and metadata across various storage solutions implemented in the SDK. This service is crucial for efficiently managing file uploads, ensuring that they are handled correctly according to the specified storage service's requirements.
The class methods offer diverse functionalities to upload files from paths, blob objects, buffer files, and NFT metadata, catering to different needs of the NFT ecosystem.
uploadFilesFromPath
- available in Node.js - Uploads files from given directory paths or specific file paths to the configured storage service and returns URLs to the uploaded files.
const paths = ['path/to/your/directory', 'path/to/your/file'];
const uploadResults = await uploadService.uploadFilesFromPath(paths);
This method returns an array of objects, each containing the file content and the URL where the file was uploaded.
type UploadServiceReturn = {
content: Blob;
url: string;
}[];
uploadBlobFiles
- Handles the upload of blob files or buffer files and returns URLs to these files, ensuring that files are not empty before upload.
const files = [new Blob(['data'], { type: 'text/plain' })];
const blobUploadResults = await uploadService.uploadBlobFiles(files);
This method returns an array of objects, each detailing the content of the uploaded file and the URL where it was uploaded.
type UploadServiceReturn = {
content: Blob;
url: string;
}[];
handleBlobUpload
- Specifically designed for uploading NFT metadata as JSON blobs, generating a URL where the metadata is stored.
const metadata = { name: 'Example NFT', description: 'This is an NFT metadata example.' };
const metadataUploadResult = await uploadService.handleBlobUpload(metadata);
This method returns an object containing the metadata blob content and the URL where the metadata was uploaded.
type UploadServiceReturn = {
content: Blob;
url: string;
};
uploadMetadataList
- Allows for batch uploading of NFT metadata, handling each metadata item individually and compiling the resulting URLs.
const metadata = [{ name: 'NFT 1' }, { name: 'NFT 2' }];
const metadataListUploadResults = await uploadService.uploadMetadataList(metadata);
This method returns an array of objects, each containing a single metadata's blob content and the URL where it was uploaded.
type UploadServiceReturn = {
content: Blob;
url: string;
}[];
The File Storage Services module provides a variety of options for storing and retrieving files, crucial for managing the digital assets related to NFTs. This module integrates with multiple storage solutions, including AWS S3, IPFS through Pinata and NFT.storage, as well as a mock storage service for testing and development purposes.
Each storage service implements the FileStorage interface, ensuring consistent API calls across different storage backends.
The AWSService class facilitates the upload of files to AWS S3. It provides robust error handling and flexible configuration for file uploads, including setting access permissions and handling multipart uploads.
const awsService = new AWSService(accessKeyId, secretAccessKey, region, bucketName);
const uploadUrl = await awsService.uploadFile(fileBlob);
This method returns a string containing the URL to the uploaded file.
type UploadResult = {
url: string;
};
The PinataService class allows for the pinning of files to IPFS via the Pinata Cloud service. It supports metadata and pinning options, providing a direct ipfs:// URL upon successful upload.
const pinataService = new PinataService(jwtKey);
const ipfsUrl = await pinataService.uploadFile(fileBlob);
This method returns a string containing the IPFS URL of the pinned file.
type UploadResult = {
url: string;
};
The NftStorageService integrates with the NFT.storage platform to upload files directly to IPFS, simplifying the process of storing NFT assets. It allows for dynamic API key usage, ensuring flexibility and security.
const nftStorageService = new NftStorageService(apiKeys);
const ipfsUrl = await nftStorageService.uploadFile(fileBlob);
This method returns a string containing the IPFS URL of the uploaded file.
type UploadResult = {
url: string;
};
The MockStorageService is designed for development and testing purposes, providing a straightforward implementation that returns a predefined URL.
const mockService = new MockStorageService(serviceUrl);
const mockUrl = await mockService.uploadFile();
This method returns a string containing the predefined URL.
type UploadResult = {
url: string;
};
- Local metadata validator
- Convert Metadata Objects to JSON Files
- Upload Service - uploadFilesFromPath
Listed features utilized in browser environment will throw an error.
After downloading the repo run npm run build
to build the SDK.
The validateCollectionMetadata
validates the metadata of a collection against the HIP-766 metadata schema using a specified IPFS gateway to retrieve the metadata. This method ensures that the metadata conforms to the standards required for NFT collections on the Hedera network, offering a comprehensive check that highlights any errors or missing fields in the metadata structure.
const collectionMetadataValidationResult = await validateCollectionMetadata(metadataURL, ipfsGateway);
metadataURL
: The URL or CID pointing to the metadata file. This can be a direct HTTP(S) URL or an IPFS CID. If only a CID is provided, an IPFS gateway URL must be specified unless the CID is already included in a full URL format.ipfsGateway
: Optional. Specifies the IPFS gateway URL to be used for resolving a CID to an HTTP URL. If not provided, and a CID without a full URL is used, the method will throw an error indicating the necessity for an IPFS gateway.
This method returns an object that contains:
isValid
: A boolean flag indicating whether the metadata conforms to the HIP-766 metadata schema.errors
: An array of strings detailing any issues found during the validation process. This array is empty if no errors are present.
type ValidationResult = {
isValid: boolean;
errors: string[];
};
Please create an issue or PR on this repository. Make sure to join the Hedera Discord server to ask questions or discuss improvement suggestions.
If you have a question on how to use the product, please see our support guide.
Contributions are welcome. Please see the contributing guide to see how you can get involved.
This project is governed by the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to [email protected].