diff --git a/src/networks/arbitrum.ts b/src/networks/arbitrum.ts index ccebbc83825..8a9ae182fe6 100644 --- a/src/networks/arbitrum.ts +++ b/src/networks/arbitrum.ts @@ -59,7 +59,7 @@ export const getArbitrumNetworkObject = (): NetworkProperties => { defaultSlippage: 200, }, - nfts: {}, + nfts: { simplehashNetwork: 'arbitrum' }, // design tings colors: { diff --git a/src/networks/avalanche.ts b/src/networks/avalanche.ts index 9c57bd5fddc..813fce77c90 100644 --- a/src/networks/avalanche.ts +++ b/src/networks/avalanche.ts @@ -57,7 +57,7 @@ export const getAvalancheNetworkObject = (): NetworkProperties => { defaultSlippage: 200, }, - nfts: {}, + nfts: { simplehashNetwork: 'avalanche' }, // design tings colors: { diff --git a/src/networks/base.ts b/src/networks/base.ts index 4b193782ec1..f483b210019 100644 --- a/src/networks/base.ts +++ b/src/networks/base.ts @@ -57,7 +57,7 @@ export const getBaseNetworkObject = (): NetworkProperties => { defaultSlippage: 200, }, - nfts: {}, + nfts: { simplehashNetwork: 'base' }, // design tings colors: { diff --git a/src/networks/blast.ts b/src/networks/blast.ts index c1c06e4f71d..a0a7ba98d44 100644 --- a/src/networks/blast.ts +++ b/src/networks/blast.ts @@ -60,7 +60,7 @@ export const getBlastNetworkObject = (): NetworkProperties => { defaultSlippage: 200, }, - nfts: {}, + nfts: { simplehashNetwork: 'blast' }, // design tings colors: { diff --git a/src/networks/bsc.ts b/src/networks/bsc.ts index 2e81bcc3cd9..f69d37a88b3 100644 --- a/src/networks/bsc.ts +++ b/src/networks/bsc.ts @@ -60,7 +60,9 @@ export const getBSCNetworkObject = (): NetworkProperties => { defaultSlippage: 200, }, - nfts: {}, + nfts: { + simplehashNetwork: 'bsc', + }, // design tings colors: { diff --git a/src/networks/gnosis.ts b/src/networks/gnosis.ts index 2cf11622e75..ad90dbac2d0 100644 --- a/src/networks/gnosis.ts +++ b/src/networks/gnosis.ts @@ -56,7 +56,9 @@ export const getGnosisNetworkObject = (): NetworkProperties => { defaultSlippage: 200, }, - nfts: {}, + nfts: { + simplehashNetwork: 'gnosis', + }, // design tings colors: { diff --git a/src/networks/goerli.ts b/src/networks/goerli.ts index ca21d270058..82e9c501ee5 100644 --- a/src/networks/goerli.ts +++ b/src/networks/goerli.ts @@ -59,7 +59,9 @@ export const getGoerliNetworkObject = (): NetworkProperties => { defaultToFastGas: true, }, - nfts: {}, + nfts: { + simplehashNetwork: 'ethereum-goerli', + }, // design tings colors: { diff --git a/src/networks/optimism.ts b/src/networks/optimism.ts index ba9a8c9944d..ade896684be 100644 --- a/src/networks/optimism.ts +++ b/src/networks/optimism.ts @@ -58,7 +58,7 @@ export const getOptimismNetworkObject = (): NetworkProperties => { defaultSlippage: 200, }, - nfts: {}, + nfts: { simplehashNetwork: 'optimism' }, // design tings colors: { diff --git a/src/networks/polygon.ts b/src/networks/polygon.ts index 24464d41743..91650074209 100644 --- a/src/networks/polygon.ts +++ b/src/networks/polygon.ts @@ -59,7 +59,7 @@ export const getPolygonNetworkObject = (): NetworkProperties => { defaultToFastGas: true, }, - nfts: {}, + nfts: { simplehashNetwork: 'polygon' }, // design tings colors: { diff --git a/src/networks/types.ts b/src/networks/types.ts index 20c09888602..072e4642814 100644 --- a/src/networks/types.ts +++ b/src/networks/types.ts @@ -71,7 +71,7 @@ export interface NetworkProperties extends Chain { }; nfts: { - simplehashNetwork?: string; + simplehashNetwork: string | null; }; // design tings diff --git a/src/resources/nfts/simplehash/index.ts b/src/resources/nfts/simplehash/index.ts index 0b9b60c4985..c8304828b54 100644 --- a/src/resources/nfts/simplehash/index.ts +++ b/src/resources/nfts/simplehash/index.ts @@ -1,11 +1,11 @@ import { NFT_API_KEY, NFT_API_URL } from 'react-native-dotenv'; import { RainbowFetchClient } from '@/rainbow-fetch'; import { Network } from '@/helpers'; -import { getSimpleHashChainFromNetwork } from '@/resources/nfts/simplehash/utils'; -import { SimpleHashChain, SimpleHashListing, SimpleHashNFT, SimpleHashMarketplaceId } from '@/resources/nfts/simplehash/types'; -import { RainbowNetworks } from '@/networks'; +import { SimpleHashListing, SimpleHashNFT, SimpleHashMarketplaceId } from '@/resources/nfts/simplehash/types'; +import { RainbowNetworks, getNetworkObj } from '@/networks'; import { UniqueAsset } from '@/entities'; import { RainbowError, logger } from '@/logger'; +import { getGnosisNetworkObject } from '@/networks/gnosis'; export const START_CURSOR = 'start'; @@ -20,10 +20,11 @@ export async function fetchSimpleHashNFT( tokenId: string, network: Omit = Network.mainnet ): Promise { - const chain = getSimpleHashChainFromNetwork(network); + const chain = getNetworkObj(network as Network).nfts.simplehashNetwork; if (!chain) { - throw new Error(`fetchSimpleHashNFT: no SimpleHash chain for network: ${network}`); + logger.error(new RainbowError(`fetchSimpleHashNFT: no SimpleHash chain for network: ${network}`)); + return; } const response = await nftApi.get(`/nfts/${chain}/${contractAddress}/${tokenId}`, { @@ -40,9 +41,10 @@ export async function fetchSimpleHashNFTs( walletAddress: string, cursor: string = START_CURSOR ): Promise<{ data: SimpleHashNFT[]; nextCursor: string | null }> { - const chainsParam = RainbowNetworks.filter(network => network.features.nfts) - .map(network => network.nfts?.simplehashNetwork || network.value) + const chainsParam = RainbowNetworks.filter(network => network.features.nfts && network.nfts.simplehashNetwork) + .map(network => network.nfts.simplehashNetwork) .join(','); + const cursorSuffix = createCursorSuffix(cursor); const response = await nftApi.get(`/nfts/owners?chains=${chainsParam}&wallet_addresses=${walletAddress}${cursorSuffix}`, { headers: { @@ -65,7 +67,12 @@ export async function fetchSimpleHashNFTListing( // array of all eth listings on OpenSea for this token let listings: SimpleHashListing[] = []; let cursor = START_CURSOR; - const chain = getSimpleHashChainFromNetwork(network); + const chain = getNetworkObj(network as Network).nfts.simplehashNetwork; + + if (!chain) { + logger.error(new RainbowError(`fetchSimpleHashNFTListing: no SimpleHash chain for network: ${network}`)); + return; + } while (cursor) { const cursorSuffix = createCursorSuffix(cursor); @@ -99,10 +106,11 @@ export async function fetchSimpleHashNFTListing( * @param nft */ export async function refreshNFTContractMetadata(nft: UniqueAsset) { - const chain = nft.isPoap ? SimpleHashChain.Gnosis : getSimpleHashChainFromNetwork(nft.network); + const chain = (nft.isPoap ? getGnosisNetworkObject() : getNetworkObj(nft.network)).nfts.simplehashNetwork; if (!chain) { logger.error(new RainbowError(`refreshNFTContractMetadata: no SimpleHash chain for network: ${nft.network}`)); + return; } try { @@ -150,10 +158,11 @@ export async function refreshNFTContractMetadata(nft: UniqueAsset) { * @param nft */ export async function reportNFT(nft: UniqueAsset) { - const chain = nft.isPoap ? SimpleHashChain.Gnosis : getSimpleHashChainFromNetwork(nft.network); + const chain = (nft.isPoap ? getGnosisNetworkObject() : getNetworkObj(nft.network)).nfts.simplehashNetwork; if (!chain) { logger.error(new RainbowError(`reportNFT: no SimpleHash chain for network: ${nft.network}`)); + return; } try { diff --git a/src/resources/nfts/simplehash/types.ts b/src/resources/nfts/simplehash/types.ts index 287360608cc..a26cddcf86b 100644 --- a/src/resources/nfts/simplehash/types.ts +++ b/src/resources/nfts/simplehash/types.ts @@ -1,18 +1,5 @@ import { Network } from '@/helpers'; -export enum SimpleHashChain { - Arbitrum = 'arbitrum', - Bsc = 'bsc', - Ethereum = 'ethereum', - Gnosis = 'gnosis', - Optimism = 'optimism', - Polygon = 'polygon', - Zora = 'zora', - Base = 'base', - Avalanche = 'avalanche', - Blast = 'blast', -} - /** * @see https://docs.simplehash.com/reference/sale-model */ @@ -100,7 +87,7 @@ type SimpleHashCollection = { */ export type SimpleHashNFT = { nft_id: string; - chain: SimpleHashChain; + chain: string; contract_address: string; token_id: string | null; name: string | null; diff --git a/src/resources/nfts/simplehash/utils.ts b/src/resources/nfts/simplehash/utils.ts index 4e4b44d5ef0..c16870bbbb2 100644 --- a/src/resources/nfts/simplehash/utils.ts +++ b/src/resources/nfts/simplehash/utils.ts @@ -1,15 +1,13 @@ -import { AssetType, AssetTypes, EthereumAddress } from '@/entities'; +import { AssetType } from '@/entities'; import { UniqueAsset } from '@/entities/uniqueAssets'; import { SimpleHashNFT, ValidatedSimpleHashNFT, - SimpleHashChain, SimpleHashFloorPrice, SimpleHashMarketplaceId, SimpleHashTrait, SimpleHashMarketplace, } from '@/resources/nfts/simplehash/types'; -import { Network } from '@/helpers/networkTypes'; import { ENS_NFT_CONTRACT_ADDRESS, ETH_ADDRESS, POAP_NFT_ADDRESS } from '@/references'; import { convertRawAmountToRoundedDecimal } from '@/helpers/utilities'; import { NFT, NFTFloorPrice, NFTMarketplace, NFTMarketplaceId, NFTTrait, PolygonAllowlist } from '../types'; @@ -22,6 +20,9 @@ import { PixelRatio } from 'react-native'; import { deviceUtils } from '@/utils'; import { TokenStandard } from '@/handlers/web3'; import { handleNFTImages } from '@/utils/handleNFTImages'; +import { RainbowNetworks } from '@/networks'; +import { getPolygonNetworkObject } from '@/networks/polygon'; +import { getGnosisNetworkObject } from '@/networks/gnosis'; const ENS_COLLECTION_NAME = 'ENS'; const SVG_MIME_TYPE = 'image/svg+xml'; @@ -32,72 +33,6 @@ const MAX_IMAGE_SCALE = 3; const FULL_NFT_IMAGE_SIZE = size * MAX_IMAGE_SCALE; const GOOGLE_USER_CONTENT_URL = 'https://lh3.googleusercontent.com/'; -// same thing here, seems like only difference is we use mainnet instead of ethereum -/** - * Returns a `SimpleHashChain` from a given `Network`. Can return undefined if - * a `Network` has no counterpart in SimpleHash. - * @param network `Network` - * @returns `SimpleHashChain` or `undefined` - */ -export function getSimpleHashChainFromNetwork(network: Omit): SimpleHashChain | undefined { - switch (network) { - case Network.mainnet: - return SimpleHashChain.Ethereum; - case Network.polygon: - return SimpleHashChain.Polygon; - case Network.arbitrum: - return SimpleHashChain.Arbitrum; - case Network.optimism: - return SimpleHashChain.Optimism; - case Network.bsc: - return SimpleHashChain.Bsc; - case Network.zora: - return SimpleHashChain.Zora; - case Network.avalanche: - return SimpleHashChain.Avalanche; - case Network.blast: - return SimpleHashChain.Blast; - default: - return undefined; - } -} - -/** - * Returns a `Network` from a `SimpleHashChain`. If an invalid value is - * forcably passed in, it will throw. - * @param chain `SimpleHashChain` - * @returns `Network` - */ -export function getNetworkFromSimpleHashChain(chain: SimpleHashChain): Network { - switch (chain) { - case SimpleHashChain.Ethereum: - case SimpleHashChain.Gnosis: - return Network.mainnet; - case SimpleHashChain.Polygon: - return Network.polygon; - case SimpleHashChain.Arbitrum: - return Network.arbitrum; - case SimpleHashChain.Optimism: - return Network.optimism; - case SimpleHashChain.Bsc: - return Network.bsc; - case SimpleHashChain.Zora: - return Network.zora; - case SimpleHashChain.Base: - return Network.base; - case SimpleHashChain.Avalanche: - return Network.avalanche; - case SimpleHashChain.Blast: - return Network.blast; - default: - /* - * Throws here because according to TS types, we should NEVER hit this - * default branch in the logic - */ - throw new Error(`getNetworkFromSimpleHashChain received unknown chain: ${chain}`); - } -} - /** * Filters out NFTs that do not have a name, collection name, * contract address, or token id, Gnosis NFTs that are not POAPs, @@ -108,30 +43,39 @@ export function getNetworkFromSimpleHashChain(chain: SimpleHashChain): Network { * @returns filtered array of `ValidatedSimpleHashNFT`s */ export function filterSimpleHashNFTs(nfts: SimpleHashNFT[], polygonAllowlist?: PolygonAllowlist): ValidatedSimpleHashNFT[] { - return nfts - .filter(nft => { - const lowercasedContractAddress = nft.contract_address?.toLowerCase(); - const network = getNetworkFromSimpleHashChain(nft.chain); + return nfts.flatMap(nft => { + const { + chain, + name, + collection: { name: collectionName }, + contract_address, + token_id, + } = nft; + + const lowercasedContractAddress = nft.contract_address?.toLowerCase(); + const network = RainbowNetworks.find(network => network.nfts.simplehashNetwork === chain)?.value; - const isMissingRequiredFields = !nft.name || !nft.collection?.name || !nft.contract_address || !nft.token_id || !network; - const isPolygonAndNotAllowed = - polygonAllowlist && nft.chain === SimpleHashChain.Polygon && !polygonAllowlist[lowercasedContractAddress]; - const isGnosisAndNotPOAP = nft.chain === SimpleHashChain.Gnosis && lowercasedContractAddress !== POAP_NFT_ADDRESS; + const isMissingRequiredFields = !name || !collectionName || !contract_address || !token_id || !network; + const isPolygonAndNotAllowed = + polygonAllowlist && nft.chain === getPolygonNetworkObject().nfts.simplehashNetwork && !polygonAllowlist[lowercasedContractAddress]; + const isGnosisAndNotPOAP = + nft.chain === getGnosisNetworkObject().nfts.simplehashNetwork && lowercasedContractAddress !== POAP_NFT_ADDRESS; - if (isMissingRequiredFields || isPolygonAndNotAllowed || isGnosisAndNotPOAP) { - return false; - } + if (isMissingRequiredFields || isPolygonAndNotAllowed || isGnosisAndNotPOAP) { + return []; + } - return true; - }) - .map(nft => ({ - ...nft, - name: nft.name!, - contract_address: nft.contract_address, - chain: getNetworkFromSimpleHashChain(nft.chain), - collection: { ...nft.collection, name: nft.collection.name! }, - token_id: nft.token_id!, - })); + return [ + { + ...nft, + name: name, + contract_address: lowercasedContractAddress, + chain: network, + collection: { ...nft.collection, name: collectionName }, + token_id: token_id, + }, + ]; + }); } /**