From a9d0057b9103c12e210e4dc3d4b700fcccb58d42 Mon Sep 17 00:00:00 2001 From: Lantt Date: Fri, 21 Jan 2022 16:47:08 +0800 Subject: [PATCH 1/3] feat: get collection from nft scan --- .../components/Wallet/CollectibleCard.tsx | 1 + .../plugins/EVM/UI/Web3State/getAssetsFn.ts | 6 ++- packages/plugin-infra/src/web3-types.ts | 2 + .../producers/nonFungibleCollectionAsset.ts | 37 +++++++++++-------- packages/web3-providers/src/NFTScan/index.ts | 5 +++ packages/web3-providers/src/index.ts | 1 + packages/web3-providers/src/opensea/index.ts | 6 +++ packages/web3-providers/src/opensea/types.ts | 6 +++ 8 files changed, 48 insertions(+), 16 deletions(-) diff --git a/packages/dashboard/stories/components/Wallet/CollectibleCard.tsx b/packages/dashboard/stories/components/Wallet/CollectibleCard.tsx index 93799c26ac15..cc9dc776ecd3 100644 --- a/packages/dashboard/stories/components/Wallet/CollectibleCard.tsx +++ b/packages/dashboard/stories/components/Wallet/CollectibleCard.tsx @@ -22,6 +22,7 @@ export const CollectibleCard = of({ mediaType: '', }, contract: { + id: 'address', address: 'address', chainId: 1, name: '', diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts b/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts index 66192f74dbde..c80f9af10eeb 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts @@ -187,7 +187,11 @@ export const getNonFungibleTokenFn = name: x.info.name ?? `${x.contractDetailed.name} ${x.tokenId}`, description: x.info.description ?? '', owner: x.info.owner, - contract: { ...x.contractDetailed, type: TokenType.NonFungible }, + contract: { + ...x.contractDetailed, + type: TokenType.NonFungible, + id: x.contractDetailed.address, + }, metadata: { name: x.info.name ?? `${x.contractDetailed.name} ${x.tokenId}`, description: x.info.description ?? '', diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index 7d033e61de20..857d05b6c551 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -162,11 +162,13 @@ export declare namespace Web3Plugin { } export interface NonFungibleContract { + id: string chainId: number name: string symbol: string address: string iconURL?: string + balance?: number } export interface FungibleTokenMetadata { diff --git a/packages/provider-proxy/src/producers/nonFungibleCollectionAsset.ts b/packages/provider-proxy/src/producers/nonFungibleCollectionAsset.ts index 5dbb53dfc5dd..96a1be2e89be 100644 --- a/packages/provider-proxy/src/producers/nonFungibleCollectionAsset.ts +++ b/packages/provider-proxy/src/producers/nonFungibleCollectionAsset.ts @@ -1,19 +1,13 @@ -import { getOpenSeaCollectionList } from '@masknet/web3-providers' +import type { Web3Plugin } from '@masknet/plugin-infra' +import { getNFTScanNFTList } from '@masknet/web3-providers' import type { ProducerArgBase, ProducerKeyFunction, ProducerPushFunction, RPCMethodRegistrationValue } from '../types' -import { collectAllPageDate } from '../helper/request' - -interface Collection { - name: string - image?: string - slug: string -} interface NonFungibleCollectibleAssetArgs extends ProducerArgBase { address: string } const nonFungibleCollectionAsset = async ( - push: ProducerPushFunction, + push: ProducerPushFunction, getKeys: ProducerKeyFunction, args: NonFungibleCollectibleAssetArgs, ): Promise => { @@ -21,17 +15,30 @@ const nonFungibleCollectionAsset = async ( const openSeaApiKey = await getKeys('opensea') const pageSize = 50 - const collectFromOpenSea = await collectAllPageDate( - (page: number) => getOpenSeaCollectionList(openSeaApiKey, address, page, pageSize), - pageSize, + const collectionsFromNFTScan = await getNFTScanNFTList(address) + await push( + collectionsFromNFTScan.map((x) => ({ + id: x.contractDetailed.address, + chainId: x.contractDetailed.chainId, + name: x.contractDetailed.name, + symbol: x.contractDetailed.symbol, + address: x.contractDetailed.address, + iconURL: x.contractDetailed.iconURL, + balance: x.balance, + })), ) - await push(collectFromOpenSea) + + // const collectionsFromOpenSea = await collectAllPageDate( + // (page: number) => getOpenSeaCollectionList(openSeaApiKey, address, page, pageSize), + // pageSize, + // ) + // await push(collectionsFromOpenSea) } -const producer: RPCMethodRegistrationValue = { +const producer: RPCMethodRegistrationValue = { method: 'mask.fetchNonFungibleCollectionAsset', producer: nonFungibleCollectionAsset, - distinctBy: (item) => item.name, + distinctBy: (item) => item.address, } export default producer diff --git a/packages/web3-providers/src/NFTScan/index.ts b/packages/web3-providers/src/NFTScan/index.ts index 3bfb6fe3faf1..5d8f0db17aa7 100644 --- a/packages/web3-providers/src/NFTScan/index.ts +++ b/packages/web3-providers/src/NFTScan/index.ts @@ -116,3 +116,8 @@ export class NFTScanAPI implements NonFungibleTokenAPI.Provider { } } } + +export function getNFTScanNFTList(address: string) { + const nftScanAPI = new NFTScanAPI() + return nftScanAPI.getContractBalance(address) +} diff --git a/packages/web3-providers/src/index.ts b/packages/web3-providers/src/index.ts index d164b0078261..1555b44b07da 100644 --- a/packages/web3-providers/src/index.ts +++ b/packages/web3-providers/src/index.ts @@ -21,3 +21,4 @@ export const KeyValue = new KeyValueAPI() export { getOpenSeaNFTList, getOpenSeaCollectionList } from './opensea' export { getAssetListFromDebank } from './debank' export { getRaribleNFTList } from './rarible' +export { getNFTScanNFTList } from './NFTScan' diff --git a/packages/web3-providers/src/opensea/index.ts b/packages/web3-providers/src/opensea/index.ts index c5153b9e647e..8ba75ed1032c 100644 --- a/packages/web3-providers/src/opensea/index.ts +++ b/packages/web3-providers/src/opensea/index.ts @@ -352,6 +352,12 @@ export class OpenSeaAPI implements NonFungibleTokenAPI.Provider { name: x.name, image: x.image_url || undefined, slug: x.slug, + id: x.slug, + chainId, + symbol: x.primary_asset_contracts?.[0]?.symbol, + address: x.primary_asset_contracts?.[0]?.address, + iconURL: x.image_url, + balance: x.owned_asset_count, })) ?? [] return { diff --git a/packages/web3-providers/src/opensea/types.ts b/packages/web3-providers/src/opensea/types.ts index 64d5f2a46f82..58590dbb8119 100644 --- a/packages/web3-providers/src/opensea/types.ts +++ b/packages/web3-providers/src/opensea/types.ts @@ -78,6 +78,12 @@ export interface OpenSeaCollection extends OpenSeaFees { external_link?: string wiki_link?: string safelist_request_status: string + owned_asset_count: number + primary_asset_contracts: { + address: string + asset_contract_type: string + symbol: string + }[] } export interface OpenSeaResponse extends Asset { From 91b0b043eb6b83e8be2839f3d15ac867bb433aac Mon Sep 17 00:00:00 2001 From: Lantt Date: Fri, 21 Jan 2022 17:47:59 +0800 Subject: [PATCH 2/3] refactor: is proxy env --- packages/provider-proxy/package.json | 1 + packages/provider-proxy/rollup.config.js | 4 +++ .../producers/nonFungibleCollectionAsset.ts | 13 +++++----- packages/web3-providers/src/NFTScan/index.ts | 3 ++- packages/web3-providers/src/helpers.ts | 2 ++ packages/web3-providers/src/opensea/index.ts | 26 +++++++------------ packages/web3-providers/src/rarible/index.ts | 14 ++++------ packages/web3-providers/src/types.ts | 4 --- pnpm-lock.yaml | 17 +++++++++--- 9 files changed, 45 insertions(+), 39 deletions(-) diff --git a/packages/provider-proxy/package.json b/packages/provider-proxy/package.json index b5ea09a9fada..46809486d768 100644 --- a/packages/provider-proxy/package.json +++ b/packages/provider-proxy/package.json @@ -17,6 +17,7 @@ "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^13.0.6", + "@rollup/plugin-replace": "^3.0.1", "@rollup/plugin-sucrase": "^4.0.1", "date-fns": "^2.27.0", "rollup": "^2.60.1", diff --git a/packages/provider-proxy/rollup.config.js b/packages/provider-proxy/rollup.config.js index 0c01fd5525f2..1e9c6e55a578 100644 --- a/packages/provider-proxy/rollup.config.js +++ b/packages/provider-proxy/rollup.config.js @@ -4,6 +4,7 @@ import sucrase from '@rollup/plugin-sucrase' import json from '@rollup/plugin-json' import alias from '@rollup/plugin-alias' import dts from 'rollup-plugin-dts' +import replace from '@rollup/plugin-replace' const config = { input: './src/index.ts', @@ -22,6 +23,9 @@ const config = { ], }), sucrase({ transforms: ['typescript', 'jsx'] }), + replace({ + 'process.env.PROVIDER_API_ENV': JSON.stringify('proxy'), + }), ], external: (id) => { if (id.startsWith('.')) return false diff --git a/packages/provider-proxy/src/producers/nonFungibleCollectionAsset.ts b/packages/provider-proxy/src/producers/nonFungibleCollectionAsset.ts index 96a1be2e89be..f04ee2632978 100644 --- a/packages/provider-proxy/src/producers/nonFungibleCollectionAsset.ts +++ b/packages/provider-proxy/src/producers/nonFungibleCollectionAsset.ts @@ -1,5 +1,6 @@ import type { Web3Plugin } from '@masknet/plugin-infra' -import { getNFTScanNFTList } from '@masknet/web3-providers' +import { getNFTScanNFTList, getOpenSeaCollectionList } from '@masknet/web3-providers' +import { collectAllPageDate } from '../helper/request' import type { ProducerArgBase, ProducerKeyFunction, ProducerPushFunction, RPCMethodRegistrationValue } from '../types' interface NonFungibleCollectibleAssetArgs extends ProducerArgBase { @@ -28,11 +29,11 @@ const nonFungibleCollectionAsset = async ( })), ) - // const collectionsFromOpenSea = await collectAllPageDate( - // (page: number) => getOpenSeaCollectionList(openSeaApiKey, address, page, pageSize), - // pageSize, - // ) - // await push(collectionsFromOpenSea) + const collectionsFromOpenSea = await collectAllPageDate( + (page: number) => getOpenSeaCollectionList(openSeaApiKey, address, page, pageSize), + pageSize, + ) + await push(collectionsFromOpenSea) } const producer: RPCMethodRegistrationValue = { diff --git a/packages/web3-providers/src/NFTScan/index.ts b/packages/web3-providers/src/NFTScan/index.ts index 5d8f0db17aa7..6683679d98c9 100644 --- a/packages/web3-providers/src/NFTScan/index.ts +++ b/packages/web3-providers/src/NFTScan/index.ts @@ -5,6 +5,7 @@ import urlcat from 'urlcat' import type { NonFungibleTokenAPI } from '..' import { NFTSCAN_ACCESS_TOKEN_URL, NFTSCAN_BASE_API } from './constants' import type { NFTScanAsset, NFT_Assets } from './types' +import { isProxyENV } from '../helpers' const tokenCache = new Map<'token', { token: string; expiration: Date }>() @@ -13,7 +14,7 @@ async function getToken() { if (token && isBefore(Date.now(), token.expiration)) { return token.token } - const response = await fetch(NFTSCAN_ACCESS_TOKEN_URL, { mode: 'cors' }) + const response = await fetch(NFTSCAN_ACCESS_TOKEN_URL, { ...(!isProxyENV && { mode: 'cors' }) }) const { data, }: { diff --git a/packages/web3-providers/src/helpers.ts b/packages/web3-providers/src/helpers.ts index b4f0bf6359fd..818ef61b5e26 100644 --- a/packages/web3-providers/src/helpers.ts +++ b/packages/web3-providers/src/helpers.ts @@ -1,3 +1,5 @@ +export const isProxyENV = process.env.PROVIDER_API_ENV === 'proxy' + export async function fetchJSON(requestInfo: RequestInfo, requestInit?: RequestInit): Promise { const res = await globalThis.fetch(requestInfo, requestInit) return res.json() diff --git a/packages/web3-providers/src/opensea/index.ts b/packages/web3-providers/src/opensea/index.ts index 8ba75ed1032c..a10e492f11b1 100644 --- a/packages/web3-providers/src/opensea/index.ts +++ b/packages/web3-providers/src/opensea/index.ts @@ -13,7 +13,7 @@ import fromUnixTime from 'date-fns/fromUnixTime' import isAfter from 'date-fns/isAfter' import { head, uniqBy } from 'lodash-unified' import urlcat from 'urlcat' -import { NonFungibleTokenAPI } from '../types' +import type { NonFungibleTokenAPI } from '../types' import { getOrderUnitPrice, getOrderUSDPrice } from './utils' import type { OpenSeaAssetContract, @@ -24,15 +24,16 @@ import type { OpenSeaResponse, } from './types' import { OPENSEA_ACCOUNT_URL, OPENSEA_API_KEY, OPENSEA_API_URL } from './constants' +import { isProxyENV } from '../helpers' -async function fetchFromOpenSea(url: string, chainId: ChainId, apiKey?: string, env?: NonFungibleTokenAPI.APIEnv) { +async function fetchFromOpenSea(url: string, chainId: ChainId, apiKey?: string) { if (![ChainId.Mainnet, ChainId.Rinkeby].includes(chainId)) return - const currentEnv = env ?? NonFungibleTokenAPI.APIEnv.browser + try { const response = await fetch(urlcat(OPENSEA_API_URL, url), { method: 'GET', headers: { 'x-api-key': apiKey ?? OPENSEA_API_KEY, Accept: 'application/json' }, - ...(currentEnv === NonFungibleTokenAPI.APIEnv.browser && { mode: 'cors' }), + ...(!isProxyENV && { mode: 'cors' }), }) if (response.status === 404) return return response.json() as Promise @@ -242,10 +243,8 @@ function createAssetOrder(order: OpenSeaAssetOrder): NonFungibleTokenAPI.AssetOr export class OpenSeaAPI implements NonFungibleTokenAPI.Provider { private readonly _apiKey - private readonly _env: NonFungibleTokenAPI.APIEnv - constructor(apiKey?: string, env?: NonFungibleTokenAPI.APIEnv) { + constructor(apiKey?: string) { this._apiKey = apiKey - this._env = env ?? NonFungibleTokenAPI.APIEnv.browser } async getAsset(address: string, tokenId: string, { chainId = ChainId.Mainnet }: { chainId?: ChainId } = {}) { const requestPath = urlcat('/api/v1/asset/:address/:tokenId', { address, tokenId }) @@ -276,12 +275,7 @@ export class OpenSeaAPI implements NonFungibleTokenAPI.Provider { limit: size, collection: opts.pageInfo?.collection, }) - const response = await fetchFromOpenSea<{ assets: OpenSeaResponse[] }>( - requestPath, - chainId, - this._apiKey, - this._env, - ) + const response = await fetchFromOpenSea<{ assets: OpenSeaResponse[] }>(requestPath, chainId, this._apiKey) const assets = response?.assets .filter( @@ -339,7 +333,7 @@ export class OpenSeaAPI implements NonFungibleTokenAPI.Provider { offset: page * size, limit: size, }) - const response = await fetchFromOpenSea(requestPath, chainId, this._apiKey, this._env) + const response = await fetchFromOpenSea(requestPath, chainId, this._apiKey) if (!response) { return { data: [], @@ -368,11 +362,11 @@ export class OpenSeaAPI implements NonFungibleTokenAPI.Provider { } export function getOpenSeaNFTList(apiKey: string, address: string, page?: number, size?: number) { - const opensea = new OpenSeaAPI(apiKey, NonFungibleTokenAPI.APIEnv.proxy) + const opensea = new OpenSeaAPI(apiKey) return opensea.getTokens(address, { page, size }) } export function getOpenSeaCollectionList(apiKey: string, address: string, page?: number, size?: number) { - const opensea = new OpenSeaAPI(apiKey, NonFungibleTokenAPI.APIEnv.proxy) + const opensea = new OpenSeaAPI(apiKey) return opensea.getCollections(address, { page, size }) } diff --git a/packages/web3-providers/src/rarible/index.ts b/packages/web3-providers/src/rarible/index.ts index b267e3743f30..215e0310ed34 100644 --- a/packages/web3-providers/src/rarible/index.ts +++ b/packages/web3-providers/src/rarible/index.ts @@ -18,6 +18,7 @@ import { import { RaribleUserURL, RaribleRopstenUserURL, RaribleMainnetURL, RaribleChainURL, RaribleURL } from './constants' import { toRaribleImage } from './utils' import { NonFungibleTokenAPI } from '..' +import { isProxyENV } from '../helpers' const resolveRaribleUserNetwork = createLookupTableResolver( { @@ -27,10 +28,9 @@ const resolveRaribleUserNetwork = createLookupTableResolver(url: string, path: string, init?: RequestInit, env?: NonFungibleTokenAPI.APIEnv) { - const currentEnv = env ?? NonFungibleTokenAPI.APIEnv.browser +async function fetchFromRarible(url: string, path: string, init?: RequestInit) { const response = await fetch(urlcat(url, path), { - ...(currentEnv === NonFungibleTokenAPI.APIEnv.browser && { mode: 'cors' }), + ...(!isProxyENV && { mode: 'cors' }), ...init, }) return response.json() as Promise @@ -141,10 +141,6 @@ function _getAsset(address: string, tokenId: string) { } export class RaribleAPI implements NonFungibleTokenAPI.Provider { - private readonly _env: NonFungibleTokenAPI.APIEnv - constructor(env?: NonFungibleTokenAPI.APIEnv) { - this._env = env ?? NonFungibleTokenAPI.APIEnv.browser - } async getAsset(address: string, tokenId: string, { chainId = ChainId.Mainnet }: { chainId?: ChainId } = {}) { const asset = await _getAsset(address, tokenId) if (!asset) return @@ -167,7 +163,7 @@ export class RaribleAPI implements NonFungibleTokenAPI.Provider { continuation: string items: RaribleNFTItemMapResponse[] } - const asset = await fetchFromRarible(RaribleURL, requestPath, undefined, this._env) + const asset = await fetchFromRarible(RaribleURL, requestPath, undefined) if (!asset) return { data: [], @@ -340,6 +336,6 @@ export function getRaribleNFTList( size?: number, pageInfo?: { [key in string]: unknown }, ) { - const rarible = new RaribleAPI(NonFungibleTokenAPI.APIEnv.proxy) + const rarible = new RaribleAPI() return rarible.getTokens(address, { page, size, pageInfo }) } diff --git a/packages/web3-providers/src/types.ts b/packages/web3-providers/src/types.ts index b082ff0d23df..4aa7e93fed93 100644 --- a/packages/web3-providers/src/types.ts +++ b/packages/web3-providers/src/types.ts @@ -107,10 +107,6 @@ export namespace PriceAPI { } export namespace NonFungibleTokenAPI { - export enum APIEnv { - browser = 0, - proxy = 1, - } export enum OrderSide { Buy = 0, Sell = 1, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 96f0a81ce73d..0f8755d31020 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -836,6 +836,7 @@ importers: '@rollup/plugin-commonjs': ^21.0.1 '@rollup/plugin-json': ^4.1.0 '@rollup/plugin-node-resolve': ^13.0.6 + '@rollup/plugin-replace': ^3.0.1 '@rollup/plugin-sucrase': ^4.0.1 date-fns: ^2.27.0 rollup: ^2.60.1 @@ -852,10 +853,11 @@ importers: '@rollup/plugin-commonjs': 21.0.1_rollup@2.62.0 '@rollup/plugin-json': 4.1.0_rollup@2.62.0 '@rollup/plugin-node-resolve': 13.1.1_rollup@2.62.0 + '@rollup/plugin-replace': 3.0.1_rollup@2.62.0 '@rollup/plugin-sucrase': 4.0.1_rollup@2.62.0 date-fns: 2.27.0 rollup: 2.62.0 - rollup-plugin-dts: 4.0.1_f989a9f75f95e6331defeb4529ad92f3 + rollup-plugin-dts: 4.0.1_rollup@2.62.0 packages/public-api: specifiers: {} @@ -5369,6 +5371,16 @@ packages: rollup: 2.62.0 dev: true + /@rollup/plugin-replace/3.0.1_rollup@2.62.0: + resolution: {integrity: sha512-989J5oRzf3mm0pO/0djTijdfEh9U3n63BIXN5X7T4U9BP+fN4oxQ6DvDuBvFaHA6scaHQRclqmKQEkBhB7k7Hg==} + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 + dependencies: + '@rollup/pluginutils': 3.1.0_rollup@2.62.0 + magic-string: 0.25.7 + rollup: 2.62.0 + dev: true + /@rollup/plugin-sucrase/4.0.1_rollup@2.62.0: resolution: {integrity: sha512-VDVLl+civWOw8eLBa6jOh1SeOBWCUKTyubmi4T+Ab1eFgxUG0OqdNPXVYJbsKAOqfS+Scj5oMHXvzyJmwoJAPQ==} engines: {node: '>=12.0.0'} @@ -21348,7 +21360,7 @@ packages: dependencies: bn.js: 5.2.0 - /rollup-plugin-dts/4.0.1_f989a9f75f95e6331defeb4529ad92f3: + /rollup-plugin-dts/4.0.1_rollup@2.62.0: resolution: {integrity: sha512-DNv5F8pro/r0Hkx3JWKRtJZocDnqXfgypoajeiaNq134rYaFcEIl/oas5PogD1qexMadVijsHyVko1Chig0OOQ==} engines: {node: '>=v12.22.6'} peerDependencies: @@ -21357,7 +21369,6 @@ packages: dependencies: magic-string: 0.25.7 rollup: 2.62.0 - typescript: 4.6.0-dev.20211202 optionalDependencies: '@babel/code-frame': 7.16.0 dev: true From 2163ced67410d9acac54c161dc07c98594290d62 Mon Sep 17 00:00:00 2001 From: Lantt Date: Tue, 25 Jan 2022 13:55:15 +0800 Subject: [PATCH 3/3] fix: duplicate address in opensea format --- packages/web3-providers/src/opensea/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/web3-providers/src/opensea/index.ts b/packages/web3-providers/src/opensea/index.ts index 53a84acb4ad9..a0945570b110 100644 --- a/packages/web3-providers/src/opensea/index.ts +++ b/packages/web3-providers/src/opensea/index.ts @@ -353,7 +353,6 @@ export class OpenSeaAPI implements NonFungibleTokenAPI.Provider { address: x.primary_asset_contracts?.[0]?.address, iconURL: x.image_url, balance: x.owned_asset_count, - address: x.address, })) ?? [] return {