Skip to content

Commit

Permalink
Merge pull request #4 from Dig-A-Hash/feature/getTokenMetaData
Browse files Browse the repository at this point in the history
Feature/get token meta data
  • Loading branch information
KidSysco authored Dec 23, 2024
2 parents 3c50077 + 3194ae9 commit c885ad2
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 90 deletions.
73 changes: 51 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ const {
- **`getTokenMetaData`**: An async function to get meta data for an array of Token Ids. If chain ID is not null, then we get the meta data without needing to access the blockchain at all because we use Dig-A-Hash predictable storage paths based on that chain ID.

## useEvmNft
The useEvmNft composable fetches NFT data from an ERC721 contract and retrieves metadata either directly from the blockchain or via the Dig-A-Hash storage pattern. It supports pagination, sorting, and retrieving the current owner of a token.
The useEvmNft composable is the core composable used internally by both useEvmNftGallery, and useEvmMetaDataGallery.

This is used internally by useEvmNftGallery, and useEvmMetaDataGallery. This composable can still be used directly but the best way to use this composable is through useEvmNftGallery or useEvmMetaDataGallery as both composables will pass the public functions from useEvmNft through to the host component. For example, the functions getNftPage(), getTokenOwner(), and getTokenMetaData() returned from this useEvmNftGallery, and useEvmMetaDataGallery are passed through from useEvmNft.
This composable can be used directly to create new composables or just to use the helper functions it exposes (examples below).

- **`pageSize`** (`number`): The number of NFTs to display per page.
- **`provider`** (`object`): The `ethers.js` provider instance.
Expand All @@ -184,29 +184,58 @@ This is used internally by useEvmNftGallery, and useEvmMetaDataGallery. This com
#### Returns an object containing:
- **`getNfts`** (`function`): Fetches NFTs based on the current page, pagination size, and sorting order.
- **`getTokenOwner`** (`function`): Retrieves the owner of a specific NFT.
- **`getMetaDataBatch`** (`function`): Retrieves metadata for a batch of NFTs.
- **`getTokenMetaData`** (`function`): Retrieves metadata for specific token IDs.
- **`loadingMessage`** (`ref`): A reactive reference to track the loading status message.

#### Example Usage
### Example Usage getTokenMetaData
Easily get Dig-A-Hash Meta Data for an array of NFTs using ```getTokenMetaData```. Note that the ethers provider is not needed here, we are just fetching Meta Data using a simple http request, there will be no on-chain validation using this function.
```typescript
import {
useEvmNft,
type Nft,
} from 'vue-evm-nft';

```javascript
import { useEvmNft, blockchains, dahNftV2Abi } from 'vue-evm-nft';

const { getNfts, getTokenOwner, loadingMessage } = useEvmNft(
10, // pageSize
blockchains.fantom.publicRpc, // ethers.js provider
null, // holderPublicKey
'0xOwnerPublicKey', // contractOwnerPublicKey
'0xContractAddress', // contractAddress
dahNftV2Abi, // contractABI
1 // chainId (if applicable)
);

const loadNFTs = async () => {
const nfts = await getNfts(1, true); // Fetches the first page in ascending order
console.log(nfts);
};
const metaData = ref<Nft[]>([]);

onMounted(async () => {
const evmNft = await useEvmNft(
itemsPerPage, // This is ignored. Use any number.
null, // null Ethers provider is faster.
null,
contractPublicKey,
contractAddress,
abi,
chainId
);

metaData.value = await evmNft.getTokenMetaData([1]);
});
```

### Example Usage getTokenOwner
Get the current holder of the token using ```getTokenOwner```. The ethers provider is needed here because we need to lookup the current holder on-chain.
```typescript
import { ethers } from 'ethers'; // import ethers 6
import {
useEvmNft,
type Nft,
} from 'vue-evm-nft';

const tokenOwner = ref('');

onMounted(async () => {
const evmNft = await useEvmNft(
itemsPerPage, // This is ignored. Use any number.
new ethers.JsonRpcProvider(blockchains.avalanche.publicRpc),
null,
contractPublicKey,
contractAddress,
abi,
chainId
);

tokenOwner.value = await evmNft.getTokenOwner(1);
});
```

## useNftStore
Expand Down Expand Up @@ -290,7 +319,7 @@ nftStore.addCollection('myCollection');
nftStore.setCollectionItems(1, [{ tokenId: 1, metaData: {} }], 'myCollection');

// Retrieve a large image URL for an NFT
const largeImageUrl = nftStore.getImageLarge(nft.metaData);
const largeImageUrl = nftStore.getImageLarge(nft.metaData.image);

// Get a specific public attribute value from the NFT metadata
const attributeValue = nftStore.getPublicAttributeValue(nft.metaData, 'rarity');
Expand Down
43 changes: 26 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vue-evm-nft",
"version": "1.2.1",
"version": "1.2.2",
"main": "src/index.js",
"types": "src/types/index.d.ts",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/types/useEvmMetaDataGallery.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ export declare function useEvmMetaDataGallery(config: EvmMetaDataOptions): {
toggleSortOrder: () => Promise<void>;
getNftPage: (iPage: number) => Promise<void>;
getTokenOwner: (tokenId: number) => Promise<string>;
getTokenMetaData: (tokenIds: number[]) => Promise<object>;
getTokenMetaData: (tokenIds: number[]) => Promise<NftMetaData[]>;
};
41 changes: 4 additions & 37 deletions src/types/useEvmNft.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Ref } from 'vue';
import { ethers } from 'ethers';
import { NftMetaData } from './useNftStore';
import { Nft, NftMetaData } from './useNftStore';

/**
* Composable for interacting with EVM-based NFT contracts.
Expand All @@ -16,7 +16,7 @@ import { NftMetaData } from './useNftStore';
*/
export declare function useEvmNft(
pageSize: number,
provider: ethers.JsonRpcProvider,
provider: ethers.JsonRpcProvider | null,
holderPublicKey: string | null,
contractOwnerPublicKey: string,
contractAddress: string,
Expand All @@ -34,51 +34,18 @@ export declare function useEvmNft(
page: number,
isAscending: boolean
) => Promise<{
tokens: Array<{
tokenId: number;
metaData: NftMetaData | null;
metaDataUrl: string;
owner: string | null;
privateData: object | null;
}>;
tokens: Nft[];
pageSize: number;
count: number;
}>;

/**
* Fetches metadata for a batch of token IDs.
*
* @param batchedTokenIds - Array of objects with `tokenId` and `owner` properties.
* @param isAscending - Whether to sort metadata in ascending order.
* @returns Promise resolving to an array of tokens with metadata and owner information.
*/
getMetaDataBatch: (
batchedTokenIds: Array<{ tokenId: number; owner: string | null }>,
isAscending: boolean
) => Promise<
Array<{
tokenId: number;
metaDataUrl: string;
metaData: NftMetaData | null;
privateData: object | null;
owner: string | null;
}>
>;

/**
* Fetches metadata for a list of token IDs.
*
* @param tokenIds - Array of token IDs.
* @returns Promise resolving to an array of token objects with metadata.
*/
getTokenMetaData: (tokenIds: number[]) => Promise<
Array<{
tokenId: number;
metaDataUrl: string;
metaData: NftMetaData | null;
privateData: object | null;
}>
>;
getTokenMetaData: (tokenIds: number[]) => Promise<Nft[]>;

/**
* Fetches the owner of a specific token.
Expand Down
6 changes: 3 additions & 3 deletions src/types/useEvmNftGallery.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type ref, Ref } from 'vue';
import { NftMetaData } from './useNftStore';
import { type Nft } from './useNftStore';

/**
* The EvmNftOptions configuration object for the useEvmNftGallery composable.
Expand Down Expand Up @@ -33,12 +33,12 @@ export interface EvmNftOptions {
export declare function useEvmNftGallery(config: EvmNftOptions): {
page: ref<number>;
numberOfPages: ref<number>;
nfts: ref<NftMetaData[]>;
nfts: Ref<Nft[]>;
isAscending: ref<boolean>;
isLoading: ref<boolean>;
loadingMessage: ref<string>;
toggleSortOrder: () => Promise<void>;
getNftPage: (iPage: number) => Promise<void>;
getTokenOwner: (tokenId: number) => Promise<string>;
getTokenMetaData: (tokenIds: number[]) => Promise<object>;
getTokenMetaData: (tokenIds: number[]) => Promise<Nft[]>;
};
11 changes: 9 additions & 2 deletions src/types/useNftStore.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { StoreDefinition } from 'pinia';

interface MetaDataAttribute {
export interface MetaDataAttribute {
trait_type: string;
value: string;
}

export interface NftMetaData {
image: string;
name: string;
tokenId?: number;
description: string;
attributes?: MetaDataAttribute[];
}

export interface Nft {
tokenId: number;
metaData: NftMetaData;
metaDataUrl: string;
owner: string | null;
privateData: object | null;
}

export interface NftCollection {
items: Record<number, NftMetaData[]>; // Items are stored by page number.
itemCount: number; // Total number of items in the collection.
Expand Down
2 changes: 1 addition & 1 deletion tests/dahDemoV1/useEvmNftGallery.history.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ test('should fetch page 1 of all NFTs on contract in desc order', async (t) => {
abi: dahDemoV1Abi,
chainId: blockchains.fantom.chainId,
holderPublicKey: null,
chainId: blockchains.fantom.publicRpc,
rpc: blockchains.fantom.publicRpc,
itemsPerPage: 24,
nftStoreItemCollectionName: 'a1',
isAscendingSort: false,
Expand Down
4 changes: 2 additions & 2 deletions tests/dahDemoV1/useEvmNftGallery.holder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ test('should fetch page 1 of NFTs by holder', async (t) => {
contractAddress,
abi: dahDemoV1Abi,
chainId,
contractPublicKey,
holderPublicKey: contractPublicKey,
rpc: blockchains.avalanche.publicRpc,
itemsPerPage,
nftStoreItemCollectionName,
Expand Down Expand Up @@ -65,7 +65,7 @@ test('should fetch page 2 of NFTs by holder', async (t) => {
contractAddress,
abi: dahDemoV1Abi,
chainId,
contractPublicKey,
holderPublicKey: contractPublicKey,
rpc: blockchains.avalanche.publicRpc,
itemsPerPage,
nftStoreItemCollectionName,
Expand Down
2 changes: 1 addition & 1 deletion tests/dahNftV2/useEvmNftGallery.history.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ test('should fetch page 2 of all NFTs on contract', async (t) => {
abi: dahNftV2Abi,
chainId,
holderPublicKey: null,
rpc: blockchains.polygon.publicRpc, // otherwise batch too large
rpc: blockchains.polygon.altPublicRpc[2], // otherwise batch too large
itemsPerPage,
nftStoreItemCollectionName,
isAscendingSort: true,
Expand Down
6 changes: 3 additions & 3 deletions tests/dahNftV2/useEvmNftGallery.holder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ test('should fetch page 1 of NFTs by holder', async (t) => {
contractAddress,
abi: dahNftV2Abi,
chainId,
contractPublicKey,
holderPublicKey: contractPublicKey,
rpc: blockchains.polygon.publicRpc,
itemsPerPage,
nftStoreItemCollectionName,
Expand Down Expand Up @@ -65,8 +65,8 @@ test('should fetch page 2 of NFTs by holder', async (t) => {
contractAddress,
abi: dahNftV2Abi,
chainId,
contractPublicKey,
rpc: blockchains.polygon.publicRpc, // otherwise batch too large
holderPublicKey: contractPublicKey,
rpc: blockchains.polygon.altPublicRpc[2], // otherwise batch too large
itemsPerPage,
nftStoreItemCollectionName,
isAscendingSort: true,
Expand Down

0 comments on commit c885ad2

Please sign in to comment.