diff --git a/packages/extension/src/libs/keyring/public-keyring.ts b/packages/extension/src/libs/keyring/public-keyring.ts index 87fbc4349..c9a2048e8 100644 --- a/packages/extension/src/libs/keyring/public-keyring.ts +++ b/packages/extension/src/libs/keyring/public-keyring.ts @@ -64,8 +64,11 @@ class PublicKeyRing { walletType: WalletType.mnemonic, isHardware: false, }; - allKeys["ltc1qccf4af6j3xm9v3r6ujt7dlmvazywzq82hnuwgx"] = { - address: "ltc1qccf4af6j3xm9v3r6ujt7dlmvazywzq82hnuwgx", + allKeys[ + "bc1puzz9tmxawd7zdd7klfgtywrgpma3u22fz5ecxhucd4j8tygqe5ms2vdd9y" + ] = { + address: + "bc1puzz9tmxawd7zdd7klfgtywrgpma3u22fz5ecxhucd4j8tygqe5ms2vdd9y", basePath: "m/49'/2'/0'/1", name: "fake ltc account #4", pathIndex: 0, diff --git a/packages/extension/src/libs/nft-handlers/simplehash-ordinals.ts b/packages/extension/src/libs/nft-handlers/simplehash-ordinals.ts new file mode 100644 index 000000000..bbe5d0773 --- /dev/null +++ b/packages/extension/src/libs/nft-handlers/simplehash-ordinals.ts @@ -0,0 +1,81 @@ +import { NFTCollection, NFTItem } from "@/types/nft"; +import cacheFetch from "../cache-fetch"; +import { NetworkNames } from "@enkryptcom/types"; +import { SHNFTType, SHResponse } from "./types/simplehash"; +import { BaseNetwork } from "@/types/base-network"; +const SH_ENDPOINT = "https://partners.mewapi.io/nfts/"; +const CACHE_TTL = 60 * 1000; +const getExternalURL = (network: BaseNetwork, contract: string, id: string) => { + if (network.name === NetworkNames.Gnosis) + return `https://niftyfair.io/gc/asset/${contract}/${id}/`; + return ""; +}; +export default async ( + network: BaseNetwork, + address: string +): Promise => { + const supportedNetworks = { + [NetworkNames.Bitcoin]: "bitcoin", + }; + if (!Object.keys(supportedNetworks).includes(network.name)) + throw new Error("Simplehash: network not supported"); + let allItems: SHNFTType[] = []; + const fetchAll = (continuation?: string): Promise => { + const query = continuation + ? continuation + : `${SH_ENDPOINT}owners?chains=${ + supportedNetworks[network.name as keyof typeof supportedNetworks] + }&wallet_addresses=${network.displayAddress(address)}`; + return cacheFetch( + { + url: query, + }, + CACHE_TTL + ).then((json) => { + const items: SHNFTType[] = (json.result as SHResponse).nfts; + allItems = allItems.concat(items); + if (json.result.next) return fetchAll(json.result.next); + }); + }; + await fetchAll(); + if (!allItems || !allItems.length) return []; + const collections: Record = {}; + allItems.forEach((item) => { + if (!item.image_url && !item.previews.image_medium_url) return; + if (!item.collection.name) return; + if (collections[item.collection.collection_id]) { + const tItem: NFTItem = { + contract: item.contract_address, + id: item.nft_id, + image: item.previews.image_medium_url, + name: item.contract.name, + url: + item.external_url || + getExternalURL(network, item.contract_address, item.token_id), + }; + collections[item.collection.collection_id].items.push(tItem); + } else { + const ret: NFTCollection = { + name: item.collection.name, + description: item.collection.description, + image: + item.collection.image_url || + require("@action/assets/common/not-found.jpg"), + contract: item.contract_address, + items: [ + { + contract: item.contract_address, + id: item.nft_id, + image: item.image_url || item.previews.image_medium_url, + name: item.contract.name, + url: + item.external_url || + getExternalURL(network, item.contract_address, item.token_id), + }, + ], + }; + collections[item.collection.collection_id] = ret; + } + }); + return Object.values(collections); +}; diff --git a/packages/extension/src/libs/nft-handlers/types/simplehash.ts b/packages/extension/src/libs/nft-handlers/types/simplehash.ts index 3b6d951df..6b89545d1 100644 --- a/packages/extension/src/libs/nft-handlers/types/simplehash.ts +++ b/packages/extension/src/libs/nft-handlers/types/simplehash.ts @@ -19,6 +19,10 @@ export interface SHNFTType { description: string; image_url: string; external_url: string; + collection_id: string; + }; + contract: { + name: string; }; } export interface SHResponse { diff --git a/packages/extension/src/providers/bitcoin/networks/bitcoin.ts b/packages/extension/src/providers/bitcoin/networks/bitcoin.ts index ae101cae4..e95055081 100644 --- a/packages/extension/src/providers/bitcoin/networks/bitcoin.ts +++ b/packages/extension/src/providers/bitcoin/networks/bitcoin.ts @@ -8,7 +8,7 @@ import { haskoinHandler } from "../libs/activity-handlers"; import wrapActivityHandler from "@/libs/activity-state/wrap-activity-handler"; import BTCFeeHandler from "../libs/btc-fee-handler"; import HaskoinAPI from "../libs/api"; -import shNFTHandler from "@/libs/nft-handlers/simplehash"; +import shNFTHandler from "@/libs/nft-handlers/simplehash-ordinals"; const bitcoinOptions: BitcoinNetworkOptions = { name: NetworkNames.Bitcoin, diff --git a/packages/extension/src/providers/bitcoin/types/bitcoin-network.ts b/packages/extension/src/providers/bitcoin/types/bitcoin-network.ts index 6e1c50428..66f2ea068 100644 --- a/packages/extension/src/providers/bitcoin/types/bitcoin-network.ts +++ b/packages/extension/src/providers/bitcoin/types/bitcoin-network.ts @@ -72,6 +72,10 @@ export class BitcoinNetwork extends BaseNetwork { address: string ) => Promise; feeHandler: () => Promise>; + NFTHandler?: ( + network: BaseNetwork, + address: string + ) => Promise; constructor(options: BitcoinNetworkOptions) { const api = async () => { const api = new options.apiType(options.node, options.networkInfo); @@ -92,6 +96,7 @@ export class BitcoinNetwork extends BaseNetwork { this.activityHandler = options.activityHandler; this.networkInfo = options.networkInfo; this.feeHandler = options.feeHandler; + this.NFTHandler = options.NFTHandler; this.dust = options.dust; }