Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into 25-as-a-user-i-want-to-define-fees-for-the-c…
Browse files Browse the repository at this point in the history
…ollection

# Conflicts:
#	src/HederaNFTSDK.ts
#	src/types/validateProps.ts
#	src/utils/validateProps.ts
#	test/e2e/createCollectionE2E.test.ts
#	test/e2e/e2eConsts.ts
#	test/unit/validateProps.test.ts
  • Loading branch information
StanislawMazowieckiAriane committed Feb 8, 2024
2 parents 696821b + 8f9a4ad commit 095ccb5
Show file tree
Hide file tree
Showing 17 changed files with 354 additions and 54 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"size": "size-limit",
"start": "dts watch",
"test": "dts test --testPathIgnorePatterns=\"<rootDir>/test/e2e/\"",
"test:e2e": "dts test test/e2e --verbose"
"test:e2e": "dts test test/e2e --verbose",
"test:single": "dts test --testPathPattern"
},
"prettier": {
"printWidth": 100,
Expand Down
38 changes: 33 additions & 5 deletions src/HederaNFTSDK.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { Client, CustomFee, CustomFixedFee, CustomRoyaltyFee, PrivateKey } from '@hashgraph/sdk';
import { CreateCollectionKeysType } from './types/createCollection';
import { Client, CustomFee, NftId, PrivateKey } from '@hashgraph/sdk';
import { NetworkName } from '@hashgraph/sdk/lib/client/Client';
import { createCollectionFunction } from './functions/createCollection';
import { logIn } from './functions/logIn';
import { createJsonMetadataFromCSV } from './functions/createJsonMetadataFromCSV';
import { increaseNFTSupply } from './functions/increaseNFTSupply';
import { logIn } from './functions/logIn';
import { mintSharedMetadataFunction } from './functions/mintSharedMetadataFunction';
import { mintUniqueMetadataFunction } from './functions/mintUniqueMetadataFunction';
import { CreateCollectionKeysType } from './types/createCollection';
import { JsonMetadataFromCSVInterface } from './types/jsonMetadataFromCSV';

export class HederaNFTSDK {
accountId: string;
privateKey: string;
client: Client;
network: NetworkName;

constructor(accountId: string, privateKey: string) {
constructor(accountId: string, privateKey: string, network: NetworkName) {
this.accountId = accountId;
this.privateKey = privateKey;
this.client = logIn({ myAccountId: accountId, myPrivateKey: privateKey });
this.client = logIn({ myAccountId: accountId, myPrivateKey: privateKey, network: network });
this.network = network;
}

createCollection({
Expand Down Expand Up @@ -109,4 +113,28 @@ export class HederaNFTSDK {
metadataArray: metadata,
});
}

increaseNFTSupply({
nftId,
amount,
batchSize = 5,
supplyKey,
mirrorNodeUrl,
}: {
nftId: NftId;
amount: number;
batchSize?: number;
supplyKey?: PrivateKey;
mirrorNodeUrl?: string;
}) {
return increaseNFTSupply({
client: this.client,
network: this.network,
nftId,
amount,
batchSize,
supplyKey: supplyKey || PrivateKey.fromString(this.privateKey),
mirrorNodeUrl,
});
}
}
32 changes: 32 additions & 0 deletions src/functions/increaseNFTSupply.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NftId } from '@hashgraph/sdk';
import axios from 'axios';
import { IncreaseNFTSupplyType } from '../types/mintToken';
import { validatePropsForIncreaseNFTSupply } from '../utils/validateProps';
import { mintSharedMetadataFunction } from './mintSharedMetadataFunction';

export const increaseNFTSupply = async ({
client,
network,
nftId,
amount,
batchSize,
supplyKey,
mirrorNodeUrl
}: IncreaseNFTSupplyType) => {
validatePropsForIncreaseNFTSupply({ nftId, amount, supplyKey, batchSize });
return getMetaDataFromMirrorNode(network, nftId, mirrorNodeUrl)
.then((metaData) => mintSharedMetadataFunction({ client, tokenId: nftId.tokenId.toString(), amount, batchSize, metaData, supplyKey }));
};

async function getMetaDataFromMirrorNode(network: string, nftId: NftId, mirrorNodeUrl?: string): Promise<string> {
const url = mirrorNodeUrl || getMirrorNodeUrlForNetwork(network);
return axios.get(`${url}/tokens/${nftId.tokenId.toString()}/nfts/${nftId.serial.toString()}`)
.then((response) => {
//atob is used to decode the base64 encoded metadata
return atob(response.data.metadata);
})
}

function getMirrorNodeUrlForNetwork(network: string): string {
return `https://${network === 'mainnet' ? 'mainnet-public' : network}.mirrornode.hedera.com/api/v1`;
}
4 changes: 2 additions & 2 deletions src/functions/logIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Client } from '@hashgraph/sdk';
import { LogInType } from '../types/logIn';
import { dictionary } from '../utils/constants/dictionary';

export const logIn = ({ myAccountId, myPrivateKey }: LogInType): Client => {
export const logIn = ({ myAccountId, myPrivateKey, network }: LogInType): Client => {
if (!myAccountId) throw new Error(dictionary.createCollection.myAccountIdRequired);
if (!myPrivateKey) throw new Error(dictionary.createCollection.myPrivateKeyRequired);
return Client.forTestnet().setOperator(myAccountId, myPrivateKey);
return Client.forName(network).setOperator(myAccountId, myPrivateKey);
};
8 changes: 4 additions & 4 deletions src/functions/mintSharedMetadataFunction.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { MintedNFTType, MintTokenType } from '../types/mintToken';
import { mintToken } from './mintToken';
import { validateProps } from '../utils/validateProps';
import { MintingError } from '../utils/mintingError';
import { dictionary } from '../utils/constants/dictionary';
import { MintingError } from '../utils/mintingError';
import { validatePropsForSharedNFTMinting } from '../utils/validateProps';
import { mintToken } from './mintToken';

export const mintSharedMetadataFunction = async ({
client,
Expand All @@ -12,7 +12,7 @@ export const mintSharedMetadataFunction = async ({
metaData,
supplyKey,
}: MintTokenType) => {
validateProps({ tokenId, amount, metaData, supplyKey, batchSize });
validatePropsForSharedNFTMinting({ tokenId, amount, metaData, supplyKey, batchSize });

const mintedNFTs: MintedNFTType[] = [];
// Example if amount = 8 and batchSize = 5. NumberOfCalls should be 2. So 8/5 = 1.6. Math.ceil(1.6) = 2. Because Math.ceil rounds up to the next largest integer.
Expand Down
1 change: 1 addition & 0 deletions src/types/logIn.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type LogInType = {
myAccountId: string;
myPrivateKey: string;
network: string;
};
12 changes: 11 additions & 1 deletion src/types/mintToken.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Client, PrivateKey } from '@hashgraph/sdk';
import { Client, NftId, PrivateKey } from '@hashgraph/sdk';

export type MintUniqueTokenType = {
client: Client;
Expand All @@ -18,4 +18,14 @@ export type MintTokenType = {
supplyKey: PrivateKey;
};

export type IncreaseNFTSupplyType = {
client: Client;
network: string;
nftId: NftId;
amount: number;
batchSize: number;
supplyKey: PrivateKey;
mirrorNodeUrl?: string;
};

export type MintedNFTType = { serialNumber: number; content: string };
11 changes: 9 additions & 2 deletions src/types/validateProps.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Client, CustomFee, PrivateKey } from '@hashgraph/sdk';
import { Client, NftId, PrivateKey, CustomFee } from '@hashgraph/sdk';

export type PropsType = {
export type sharedMintingValidationProps = {
batchSize?: number;
tokenId?: string;
amount?: number;
Expand All @@ -16,6 +16,13 @@ export type uniqueMintingValidationProps = {
metadataArray?: string[];
};

export type increaseNFTSupplyValidationProps = {
nftId?: NftId;
batchSize?: number;
amount?: number;
supplyKey?: PrivateKey;
};

export type validateCreateCollectionProps = {
client?: Client;
collectionName?: string;
Expand Down
1 change: 1 addition & 0 deletions src/utils/constants/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const dictionary = {
maxBatchSize: 'Max Buffer exceeded. Use batchSize smaller of equal to 10',
minBatchSize: 'Min Buffer exceeded. Use batchSize greater than 0',
tokenIdRequired: 'tokenId is required',
nftIdRequired: 'nftId is required',
minAmount: 'Amount needs to be greater than 0',
metadataRequired: 'metadata is required',
supplyKeyRequired: 'supplyKey is required',
Expand Down
28 changes: 21 additions & 7 deletions src/utils/validateProps.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {
PropsType,
sharedMintingValidationProps,
validateCreateCollectionProps,
uniqueMintingValidationProps,
increaseNFTSupplyValidationProps,
fixedFeeValidationProps,
royaltyFeeValidationProps,
} from '../types/validateProps';
import { dictionary } from './constants/dictionary';

export const validateProps = (props: PropsType) => {
export const validatePropsForSharedNFTMinting = (props: sharedMintingValidationProps) => {
validateSupplyKey(props);
validateBatchSize(props);
validateTokenId(props);
Expand Down Expand Up @@ -76,6 +77,13 @@ const validateCustomFees = (props: validateCreateCollectionProps) => {
}
};

export const validatePropsForIncreaseNFTSupply = (props: increaseNFTSupplyValidationProps) => {
validateSupplyKey(props);
validateBatchSize(props);
validateNFTId(props);
validateAmount(props);
}

const validateAccountAndPrivateKey = (props: validateCreateCollectionProps) => {
if (
Object.prototype.hasOwnProperty.call(props, 'treasuryAccount') ||
Expand Down Expand Up @@ -109,33 +117,39 @@ const validateClient = (props: validateCreateCollectionProps) => {
}
};

const validateSupplyKey = (props: PropsType) => {
const validateSupplyKey = (props: sharedMintingValidationProps) => {
if (Object.prototype.hasOwnProperty.call(props, 'supplyKey')) {
if (!props.supplyKey) throw new Error(dictionary.hederaActions.supplyKeyRequired);
}
};

const validateBatchSize = (props: PropsType) => {
const validateBatchSize = (props: sharedMintingValidationProps) => {
if (Object.prototype.hasOwnProperty.call(props, 'batchSize')) {
if (!props.batchSize) throw new Error(dictionary.mintToken.batchSizeUndefined);
if (props.batchSize > 10) throw new Error(dictionary.hederaActions.maxBatchSize);
if (props.batchSize < 1) throw new Error(dictionary.hederaActions.minBatchSize);
}
};

const validateTokenId = (props: PropsType) => {
const validateTokenId = (props: sharedMintingValidationProps) => {
if (Object.prototype.hasOwnProperty.call(props, 'tokenId')) {
if (!props.tokenId) throw new Error(dictionary.hederaActions.tokenIdRequired);
}
};

const validateAmount = (props: PropsType) => {
const validateNFTId = (props: increaseNFTSupplyValidationProps) => {
if (Object.prototype.hasOwnProperty.call(props, 'nftId')) {
if (!props.nftId) throw new Error(dictionary.hederaActions.nftIdRequired);
}
};

const validateAmount = (props: sharedMintingValidationProps) => {
if (Object.prototype.hasOwnProperty.call(props, 'amount')) {
if (!props.amount || props.amount < 1) throw new Error(dictionary.hederaActions.minAmount);
}
};

const validateMetaData = (props: PropsType) => {
const validateMetaData = (props: sharedMintingValidationProps) => {
if (Object.prototype.hasOwnProperty.call(props, 'metaData')) {
if (!props.metaData) throw new Error(dictionary.hederaActions.metadataRequired);
}
Expand Down
1 change: 1 addition & 0 deletions test/__mocks__/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ export const JSON_METADATA_UNIT_TESTS_OUTPUT_NEW_METADATA_FOLDER_PATH =
'test/unit/output/newMetadata';

export const LONG_E2E_TIMEOUT = 25000;
export const MIRROR_NODE_DELAY = 5000;
10 changes: 2 additions & 8 deletions test/e2e/createCollectionE2E.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { PrivateKey } from '@hashgraph/sdk';
import { nftSDK, secondAccountId, secondPrivateKey } from './e2eConsts';
import { beforeEach } from 'node:test';
import { HederaNFTSDK } from '../../src';
import { LONG_E2E_TIMEOUT, myAccountId, myPrivateKey } from '../__mocks__/consts';
import { getTokenInfo } from '../../src/utils/hedera/getTokenInfo';

beforeEach(async () => {
new HederaNFTSDK(myAccountId, myPrivateKey);
});
import { LONG_E2E_TIMEOUT } from '../__mocks__/consts';
import { nftSDK, secondAccountId, secondPrivateKey } from './e2eConsts';

afterAll(async () => {
nftSDK.client.close();
Expand Down
6 changes: 3 additions & 3 deletions test/e2e/e2eConsts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { HederaNFTSDK } from '../../src/HederaNFTSDK';
import 'dotenv/config';
import { FeeFactory } from '../../src/FeeFactory';

export const operatorAccountId = process.env.SECOND_ACCOUNT_ID!;
export const operatorPrivateKey = process.env.SECOND_PRIVATE_KEY!;
export const operatorAccountId = process.env.FIRST_ACCOUNT_ID!;
export const operatorPrivateKey = process.env.FIRST_PRIVATE_KEY!;

export const secondAccountId = process.env.SECOND_ACCOUNT_ID!;
export const secondPrivateKey = process.env.SECOND_PRIVATE_KEY!;

export const nftSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey);
export const nftSDK = new HederaNFTSDK(operatorAccountId, operatorPrivateKey, 'testnet');

export const feeFactoryInstance = new FeeFactory();
52 changes: 52 additions & 0 deletions test/e2e/increaseNFTSupplyFunctionE2E.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { NftId, PrivateKey, TokenId, TokenNftInfoQuery } from '@hashgraph/sdk';
import { nftSDK, operatorPrivateKey } from './e2eConsts';
import { LONG_E2E_TIMEOUT, MIRROR_NODE_DELAY } from '../__mocks__/consts';

afterAll(async () => {
nftSDK.client.close();
});

describe('increaseNFTSupply function e2e', () => {
const testCases = [{ amount: 1 }, { amount: 3 }, { amount: 10 }];

testCases.forEach(({ amount }) => {
it(
`Increasing a token supply by ${amount}`,
async () => {
const tokenId = await nftSDK.createCollection({
collectionName: 'test_name',
collectionSymbol: 'test_symbol',
});
const baseNFT = await nftSDK.mintUniqueMetadata({
tokenId,
batchSize: 10,
metadata: ['www.youtube.com'],
supplyKey: PrivateKey.fromString(operatorPrivateKey),
});
const nftInfo = await new TokenNftInfoQuery()
.setNftId(new NftId(TokenId.fromString(tokenId), baseNFT[0].serialNumber))
.execute(nftSDK.client);

//wait for the collection and nfts to be available on mirror node
await new Promise((r) => setTimeout(r, MIRROR_NODE_DELAY));

const increaseSupplyResult = await nftSDK.increaseNFTSupply({
nftId: nftInfo[0].nftId,
amount,
batchSize: 10,
supplyKey: PrivateKey.fromString(operatorPrivateKey),
});

for (const mintedNft of increaseSupplyResult) {
const nftInfos = await new TokenNftInfoQuery()
.setNftId(new NftId(TokenId.fromString(tokenId), mintedNft.serialNumber))
.execute(nftSDK.client);

expect(nftInfos[0].metadata!.toString()).toEqual(baseNFT[0].content);
}

},
LONG_E2E_TIMEOUT
);
});
});
Loading

0 comments on commit 095ccb5

Please sign in to comment.