Skip to content

Commit

Permalink
feat: add getWalletNFTCollections
Browse files Browse the repository at this point in the history
  • Loading branch information
ErnoW committed Sep 6, 2022
1 parent 76e2f99 commit 7e83894
Show file tree
Hide file tree
Showing 14 changed files with 525 additions and 12 deletions.
6 changes: 6 additions & 0 deletions .changeset/serious-eagles-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@moralisweb3/evm-api': minor
'@moralisweb3/evm-utils': minor
---

Add Moralis.EvmApi.nft.getWalletNFTCollections() to return all nft collections of a specified address
8 changes: 3 additions & 5 deletions demos/cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@ async function main() {
apiKey: env['MORALIS_API_KEY'],
});

const block = await Moralis.EvmApi.native.getBlock({
blockNumberOrHash: '15305775',
const collection = await Moralis.EvmApi.nft.getWalletNFTCollections({
address: '0xbf48C4f51dD8C1a396386380c80EBfe667b3c1A7',
chain: '0x1',
});
console.log(block);
console.log(collection.raw);

const weights = await Moralis.EvmApi.info.endpointWeights();
console.log(weights.result);
}

main();
2 changes: 2 additions & 0 deletions packages/evmApi/src/EvmApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
getNFTTransfersByBlock,
getNFTTransfersFromToBlock,
getWalletNFTs,
getWalletNFTCollections,
getWalletNFTTransfers,
reSyncMetadata,
searchNFTs,
Expand Down Expand Up @@ -77,6 +78,7 @@ export class MoralisEvmApi extends ApiModule {
getNFTTransfers: this.endpoints.createPaginatedFetcher(getNFTTransfers),
syncNFTContract: this.endpoints.createFetcher(syncNFTContract),
getNFTContractTransfers: this.endpoints.createPaginatedFetcher(getNFTContractTransfers),
getWalletNFTCollections: this.endpoints.createPaginatedFetcher(getWalletNFTCollections)
};

private readonly _token = {
Expand Down
78 changes: 76 additions & 2 deletions packages/evmApi/src/generated/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export interface paths {
/** Get the transfers of the tokens matching the given parameters. */
get: operations["getNFTTransfers"];
};
"/{address}/nft/collections": {
/** Get the nft collections owned by an user */
get: operations["getWalletNFTCollections"];
};
"/{address}/nft/{token_address}": {
/**
* Get NFTs owned by the given address for a specific NFT contract address.
Expand Down Expand Up @@ -898,6 +902,31 @@ export interface components {
*/
updatedAt: string;
};
nftWalletCollections: {
/**
* @description The syncing status of the address [SYNCING/SYNCED]
* @example SYNCING
*/
status?: string;
/**
* @description The total number of matches for this query
* @example 2000
*/
total?: number;
/**
* @description The page of the current result
* @example 2
*/
page?: number;
/**
* @description The number of results per page
* @example 100
*/
page_size?: number;
/** @description The cursor to get to the next page */
cursor?: string;
result?: components["schemas"]["nftCollections"][];
};
nftCollection: {
/**
* @description The total number of matches for this query
Expand Down Expand Up @@ -936,6 +965,28 @@ export interface components {
page_size?: number;
result?: components["schemas"]["nftMetadata"][];
};
nftCollections: {
/**
* @description The address of the contract of the NFT
* @example 0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB
*/
token_address: string;
/**
* @description The type of NFT contract standard
* @example ERC721
*/
contract_type: string;
/**
* @description The name of the Token contract
* @example CryptoKitties
*/
name: string;
/**
* @description The symbol of the NFT contract
* @example RARI
*/
symbol: string;
};
nftOwner: {
/**
* @description The address of the contract of the NFT
Expand Down Expand Up @@ -1981,6 +2032,31 @@ export interface operations {
};
};
};
/** Get the nft collections owned by an user */
getWalletNFTCollections: {
parameters: {
query: {
/** The chain to query */
chain?: components["schemas"]["chainList"];
/** The desired page size of the result. */
limit?: number;
/** The cursor returned in the previous response (used to getting the next page). */
cursor?: string;
};
path: {
/** The owner wallet address of the NFT collections */
address: string;
};
};
responses: {
/** Returns a collection of NFTs owned by an user */
200: {
content: {
"application/json": components["schemas"]["nftWalletCollections"];
};
};
};
};
/**
* Get NFTs owned by the given address for a specific NFT contract address.
* * Use the token_address param to get results for a specific contract only
Expand Down Expand Up @@ -2289,8 +2365,6 @@ export interface operations {
to_date?: string;
/** The addresses to get metadata for */
addresses?: string[];
/** The token contract address */
token_address?: string;
/** The cursor returned in the previous response (used to getting the next page). */
cursor?: string;
/** The desired page size of the result. */
Expand Down
42 changes: 42 additions & 0 deletions packages/evmApi/src/resolvers/nft/getWalletNFTCollections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Camelize, toCamelCase } from '@moralisweb3/core';
import { EvmChainish, EvmAddressish, EvmAddress, EvmNftCollection } from '@moralisweb3/evm-utils';
import { operations } from '../../generated/types';
import { createPaginatedEndpointFactory, createPaginatedEndpoint, PaginatedParams } from '@moralisweb3/api-utils';
import { EvmChainResolver } from '../EvmChainResolver';

type operation = 'getWalletNFTCollections';

type QueryParams = operations[operation]['parameters']['query'];
type PathParams = operations[operation]['parameters']['path'];
type ApiParams = QueryParams & PathParams;
export interface Params extends Camelize<Omit<ApiParams, 'chain' | 'address'>>, PaginatedParams {
chain?: EvmChainish;
address: EvmAddressish;
}

type ApiResult = operations[operation]['responses']['200']['content']['application/json'];

export const getWalletNFTCollections = createPaginatedEndpointFactory((core) =>
createPaginatedEndpoint({
name: 'getWalletNFTCollections',
urlParams: ['address'],
getUrl: (params: Params) => `/${params.address}/nft/collections`,
apiToResult: (data: ApiResult, params: Params) =>
(data.result ?? []).map((collection) =>
EvmNftCollection.create(
{
...toCamelCase(collection),
chain: EvmChainResolver.resolve(params.chain, core),
tokenAddress: EvmAddress.create(collection.token_address, core),
},
core,
),
),
resultToJson: (data) => data.map((transaction) => transaction.toJSON()),
parseParams: (params: Params): ApiParams => ({
...params,
chain: EvmChainResolver.resolve(params.chain, core).apiHex,
address: EvmAddress.create(params.address, core).lowercase,
}),
}),
);
7 changes: 4 additions & 3 deletions packages/evmApi/src/resolvers/nft/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ export { getNFTTokenIdOwners } from './getNFTTokenIdOwners';
export { getNFTTrades } from './getNFTTrades';
export { getNFTTransfers } from './getNFTTransfers';
export { getNFTTransfersByBlock } from './getNFTTransfersByBlock';
export { getNFTTransfersFromToBlock } from './getNFTTransfersFromToBlock';
export { getWalletNFTCollections } from './getWalletNFTCollections'
export { getWalletNFTs } from './getWalletNFTs';
export { getWalletNFTTransfers } from './getWalletNFTTransfers';
export { reSyncMetadata } from './reSyncMetadata';
export { searchNFTs } from './searchNFTs';
export { syncNFTContract } from './syncNFTContract';
export { getWalletNFTTransfers } from './getWalletNFTTransfers';
export { getNFTTransfersFromToBlock } from './getNFTTransfersFromToBlock';
export { syncNFTContract } from './syncNFTContract';
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { MoralisCore } from '@moralisweb3/core';
import { EvmNftCollection } from './EvmNftCollection';
import { setupEvmUtils } from '../../test/setup';
import { EvmNftCollectionInput } from './types';

const exampleInput: EvmNftCollectionInput = {
chain: '0x1',
tokenAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
contractType: 'ERC721',
name: 'Test NFT',
symbol: 'TEST',
};

describe('EvmNftCollection', () => {
let core: MoralisCore;

beforeAll(() => {
core = setupEvmUtils();
});

beforeEach(() => {
core.config.reset();
});

/**
* Creation
*/
it('should create a new EvmNftCollection', () => {
const collection = EvmNftCollection.create(exampleInput);

expect(collection.chain.hex).toBe('0x1');
expect(collection.tokenAddress.checksum).toBe('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');
expect(collection.contractType).toBe('ERC721');
expect(collection.name).toBe('Test NFT');
expect(collection.symbol).toBe('TEST');
});

it('should throw an error when creating with an invalid contractType', () => {
expect(() => EvmNftCollection.create({ ...exampleInput, contractType: 'ERC100' })).toThrowErrorMatchingInlineSnapshot(
`"[C0005] Invalid NFT contract type provided"`,
);
});

/**
* Formatting
*/
it('should return formatting in json', () => {
const collection = EvmNftCollection.create(exampleInput);

const value = collection.toJSON();

expect(value).toStrictEqual({
"chain": "0x1",
"contractType": "ERC721",
"name": "Test NFT",
"symbol": "TEST",
"tokenAddress": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
});
});

it('should return a result object', () => {
const collection = EvmNftCollection.create(exampleInput);

const value = collection.result;

expect(value.chain.equals(exampleInput.chain)).toBeTruthy();
expect(value.contractType).toBe("ERC721");
expect(value.name).toBe('Test NFT');
expect(value.symbol).toBe('TEST');
expect(value.tokenAddress.equals(exampleInput.tokenAddress)).toBeTruthy();
});

/**
* Methods
*/
it('should check equality of 2 collections of the same value', () => {
const collectionA = EvmNftCollection.create(exampleInput);
const collectionB = EvmNftCollection.create(exampleInput);

expect(collectionA.equals(collectionB)).toBeTruthy();
});

it('should check equality of 2 collectiones of the same value via a static method', () => {
const collectionA = EvmNftCollection.create(exampleInput);
const collectionB = EvmNftCollection.create(exampleInput);

expect(EvmNftCollection.equals(collectionA, collectionB)).toBeTruthy();
});

it('should check inequality when chain is different', () => {
const collectionA = EvmNftCollection.create(exampleInput);
const collectionB = EvmNftCollection.create({ ...exampleInput, chain: '0x2' });

expect(collectionA.equals(collectionB)).toBeFalsy();
});

it('should check inequality when tokenAddress is different', () => {
const collectionA = EvmNftCollection.create(exampleInput);
const collectionB = EvmNftCollection.create({
...exampleInput,
tokenAddress: '0xC969E2CBF0Be089d938256ebE3931c2416D8A109',
});

expect(collectionA.equals(collectionB)).toBeFalsy();
});
});
Loading

0 comments on commit 7e83894

Please sign in to comment.