From e6d0447eaee5b2a481bc3e455b38a63a7b2bbe0f Mon Sep 17 00:00:00 2001 From: hotequil Date: Fri, 4 Oct 2024 17:27:17 -0300 Subject: [PATCH] CU-86a54gd39-BS Lib - Implement Support for Neo X NFTs --- .../CU-86a54gd39_2024-10-04-20-31.json | 10 ++ .../__tests__/GhostMarketNDSEthereum.spec.ts | 151 +++++++++++++----- .../src/__tests__/MoralisEDSEthereum.spec.ts | 2 +- .../nft-data/GhostMarketNDSEthereum.ts | 30 ++-- 4 files changed, 131 insertions(+), 62 deletions(-) create mode 100644 common/changes/@cityofzion/bs-ethereum/CU-86a54gd39_2024-10-04-20-31.json diff --git a/common/changes/@cityofzion/bs-ethereum/CU-86a54gd39_2024-10-04-20-31.json b/common/changes/@cityofzion/bs-ethereum/CU-86a54gd39_2024-10-04-20-31.json new file mode 100644 index 0000000..15bffc3 --- /dev/null +++ b/common/changes/@cityofzion/bs-ethereum/CU-86a54gd39_2024-10-04-20-31.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@cityofzion/bs-ethereum", + "comment": "Implement Neo X support for NFTs", + "type": "minor" + } + ], + "packageName": "@cityofzion/bs-ethereum" +} \ No newline at end of file diff --git a/packages/bs-ethereum/src/__tests__/GhostMarketNDSEthereum.spec.ts b/packages/bs-ethereum/src/__tests__/GhostMarketNDSEthereum.spec.ts index f335757..bae5a8d 100644 --- a/packages/bs-ethereum/src/__tests__/GhostMarketNDSEthereum.spec.ts +++ b/packages/bs-ethereum/src/__tests__/GhostMarketNDSEthereum.spec.ts @@ -3,62 +3,127 @@ import { GhostMarketNDSEthereum } from '../services/nft-data/GhostMarketNDSEther let ghostMarketNDSEthereum: GhostMarketNDSEthereum -describe.skip('GhostMarketNDSEthereum', () => { - beforeAll(() => { - ghostMarketNDSEthereum = new GhostMarketNDSEthereum(BSEthereumConstants.DEFAULT_NETWORK) - }) - - it('Get NFT', async () => { - const nft = await ghostMarketNDSEthereum.getNft({ - contractHash: '0xeb3a9a839dfeeaf71db1b4ed6a8ae0ccb171b227', - tokenId: '379', +describe('GhostMarketNDSEthereum', () => { + describe.skip('Ethereum Blockchain', () => { + beforeAll(() => { + ghostMarketNDSEthereum = new GhostMarketNDSEthereum(BSEthereumConstants.DEFAULT_NETWORK) }) - expect(nft).toEqual( - expect.objectContaining({ - id: '379', + it('Get NFT', async () => { + const nft = await ghostMarketNDSEthereum.getNft({ contractHash: '0xeb3a9a839dfeeaf71db1b4ed6a8ae0ccb171b227', - symbol: 'MOAR', - collectionImage: expect.any(String), - collectionName: '"MOAR" by Joan Cornella', - image: expect.any(String), - isSVG: expect.any(Boolean), - name: 'MOAR #379', - creator: { - address: '0xd71ef31e9d4e8674d9177c28cc2d0d633580615b', - name: undefined, - }, + tokenId: '379', }) - ) - }) - it('Get NFTS by address', async () => { - const nfts = await ghostMarketNDSEthereum.getNftsByAddress({ - address: '0xd773c81a4a855556ce2f2372b12272710b95b26c', - }) - expect(nfts.items.length).toBeGreaterThan(0) - nfts.items.forEach(nft => { expect(nft).toEqual( expect.objectContaining({ - symbol: expect.any(String), - id: expect.any(String), - contractHash: expect.any(String), + id: '379', + contractHash: '0xeb3a9a839dfeeaf71db1b4ed6a8ae0ccb171b227', + symbol: 'MOAR', + collectionImage: expect.any(String), + collectionName: '"MOAR" by Joan Cornella', + image: expect.any(String), + isSVG: expect.any(Boolean), + name: 'MOAR #379', + creator: { + address: '0xd71ef31e9d4e8674d9177c28cc2d0d633580615b', + name: undefined, + }, }) ) }) + + it('Get NFTS by address', async () => { + const nfts = await ghostMarketNDSEthereum.getNftsByAddress({ + address: '0xd773c81a4a855556ce2f2372b12272710b95b26c', + }) + expect(nfts.items.length).toBeGreaterThan(0) + nfts.items.forEach(nft => { + expect(nft).toEqual( + expect.objectContaining({ + symbol: expect.any(String), + id: expect.any(String), + contractHash: expect.any(String), + }) + ) + }) + }) + + it('Check if address has specific Token', async () => { + const address: string = '0xd773c81a4a855556ce2f2372b12272710b95b26c' + const nfts = await ghostMarketNDSEthereum.getNftsByAddress({ + address: address, + }) + for (const { contractHash } of nfts.items) { + const hasToken: boolean = await ghostMarketNDSEthereum.hasToken({ + address, + contractHash, + }) + expect(hasToken).toBeTruthy() + } + }, 60000) }) - it('Check if address has specific Token', async () => { - const address: string = '0xd773c81a4a855556ce2f2372b12272710b95b26c' - const nfts = await ghostMarketNDSEthereum.getNftsByAddress({ - address: address, + describe('Neo X Blockchain', () => { + const contractHash = '0x337015aaa325c684b175591bfed6ea3d3c351bb3' + const tokenId = '101' + const address = '0x2ee6a88f62e8645f671a1f889021b423b763f62c' + + beforeAll(() => { + ghostMarketNDSEthereum = new GhostMarketNDSEthereum(BSEthereumConstants.NEOX_MAINNET_NETWORK) }) - for (const { contractHash } of nfts.items) { - const hasToken: boolean = await ghostMarketNDSEthereum.hasToken({ - address, + + it('Should get NFT by contract hash and token id', async () => { + const nft = await ghostMarketNDSEthereum.getNft({ contractHash, tokenId }) + + expect(nft).toEqual({ + id: tokenId, contractHash, + symbol: 'XNAUTS', + collectionImage: undefined, + collectionName: 'NEONAUTS', + image: expect.any(String), + isSVG: expect.any(Boolean), + name: `NEONAUTS #${tokenId}`, + creator: { + address, + name: undefined, + }, }) - expect(hasToken).toBeTruthy() - } - }, 60000) + }) + + it('Should get NFTS by address', async () => { + const { items, nextCursor } = await ghostMarketNDSEthereum.getNftsByAddress({ address }) + + items.forEach(nft => { + expect(nft).toMatchObject({ + collectionImage: undefined, + id: expect.any(String), + contractHash, + symbol: expect.any(String), + collectionName: expect.any(String), + image: expect.any(String), + isSVG: expect.any(Boolean), + name: expect.any(String), + creator: { + address, + name: undefined, + }, + }) + }) + + expect(items.length).toBeGreaterThan(0) + expect(nextCursor).toBeTruthy() + }) + + it('Should check if address has specific token when get by address', async () => { + const { items } = await ghostMarketNDSEthereum.getNftsByAddress({ address }) + + for (const { contractHash } of items) { + const hasToken = await ghostMarketNDSEthereum.hasToken({ address, contractHash }) + + expect(hasToken).toBeTruthy() + } + }, 20000) + }) }) diff --git a/packages/bs-ethereum/src/__tests__/MoralisEDSEthereum.spec.ts b/packages/bs-ethereum/src/__tests__/MoralisEDSEthereum.spec.ts index 5f31c23..e83804e 100644 --- a/packages/bs-ethereum/src/__tests__/MoralisEDSEthereum.spec.ts +++ b/packages/bs-ethereum/src/__tests__/MoralisEDSEthereum.spec.ts @@ -978,7 +978,7 @@ describe('FlamingoEDSNeo3', () => { const ratio = await moralisEDSEthereum.getCurrencyRatio('BRL') expect(ratio).toEqual(expect.any(Number)) - }, 10000) + }, 20000) it('Should return EUR currency ratio', async () => { const ratio = await moralisEDSEthereum.getCurrencyRatio('EUR') diff --git a/packages/bs-ethereum/src/services/nft-data/GhostMarketNDSEthereum.ts b/packages/bs-ethereum/src/services/nft-data/GhostMarketNDSEthereum.ts index 563bc9a..1447a51 100644 --- a/packages/bs-ethereum/src/services/nft-data/GhostMarketNDSEthereum.ts +++ b/packages/bs-ethereum/src/services/nft-data/GhostMarketNDSEthereum.ts @@ -3,7 +3,7 @@ import qs from 'query-string' import axios from 'axios' import { RpcNDSEthereum } from './RpcNDSEthereum' -import { BSEthereumNetworkId } from '../../constants/BSEthereumConstants' +import { BSEthereumConstants, BSEthereumNetworkId } from '../../constants/BSEthereumConstants' type GhostMarketNFT = { tokenId: string @@ -40,20 +40,12 @@ type GhostMarketAssets = { assets: GhostMarketNFT[] next: string } + export class GhostMarketNDSEthereum extends RpcNDSEthereum { - static CONFIG_BY_NETWORK_ID: Partial< - Record< - BSEthereumNetworkId, - { - url: string - chain: string - } - > - > = { - '1': { - url: 'https://api.ghostmarket.io/api/v2', - chain: 'eth', - }, + static readonly BASE_URL = 'https://api.ghostmarket.io/api/v2' + static CONFIG_BY_NETWORK_ID: Partial> = { + '1': 'eth', + [BSEthereumConstants.NEOX_MAINNET_NETWORK_ID]: 'neox', } #network: Network @@ -102,17 +94,19 @@ export class GhostMarketNDSEthereum extends RpcNDSEthereum { } private getUrlWithParams(params: any) { - const config = GhostMarketNDSEthereum.CONFIG_BY_NETWORK_ID[this.#network.id] - if (!config) throw new Error('Unsupported network') + const chain = GhostMarketNDSEthereum.CONFIG_BY_NETWORK_ID[this.#network.id] + + if (!chain) throw new Error('Unsupported network') const parameters = qs.stringify( { - chain: config.chain, + chain, ...params, }, { arrayFormat: 'bracket' } ) - return `${config.url}/assets?${parameters}` + + return `${GhostMarketNDSEthereum.BASE_URL}/assets?${parameters}` } private parse(data: GhostMarketNFT) {