diff --git a/.changeset/dry-parents-breathe.md b/.changeset/dry-parents-breathe.md
new file mode 100644
index 000000000000..42c1cc409974
--- /dev/null
+++ b/.changeset/dry-parents-breathe.md
@@ -0,0 +1,7 @@
+---
+"ledger-live-desktop": patch
+"@ledgerhq/live-nft-react": patch
+"@ledgerhq/live-nft": patch
+---
+
+Plug the front with simplehash api for the rare sats table and inscriptions table
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/Item.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/Item.tsx
index 6845c31536f4..52b7b335bba0 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/Item.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/Item.tsx
@@ -2,21 +2,14 @@ import React from "react";
import RowLayout from "LLD/features/Collectibles/Ordinals/components/RareSats/RowLayout";
import IconContainer from "LLD/features/Collectibles/components/Collection/TableRow/IconContainer";
import TokenTitle from "LLD/features/Collectibles/components/Collection/TableRow/TokenTitle";
-import { RareSat } from "LLD/features/Collectibles/types/Ordinals";
import { Text, Flex } from "@ledgerhq/react-ui";
+import { RareSat } from "LLD/features/Collectibles/types/Ordinals";
-const Item = ({
- icons,
- name,
- year,
- count,
- utxo_size,
- isMultipleRow,
-}: RareSat & { isMultipleRow: boolean }) => {
+const Item = ({ icons, displayed_name, year, count, utxo_size, isMultipleRow }: RareSat) => {
const firstColumn = (
{icons && }
-
+
);
const secondColumn = (
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/helpers.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/helpers.ts
index 23e7080c2dea..23f7b0027b39 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/helpers.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/helpers.ts
@@ -1,107 +1,59 @@
import { mappingKeysWithIconAndName } from "../Icons";
-import { MappingKeys } from "LLD/features/Collectibles/types/Ordinals";
import { IconProps } from "LLD/features/Collectibles/types/Collection";
-import { RareSat } from "LLD/features/Collectibles/types/Ordinals";
-import {
- Satributes,
- Subrange,
- SatRange,
- MockedRareSat,
- Sat,
- Icons,
-} from "LLD/features/Collectibles/types/RareSats";
-
-export const processSatType = (
- type: string,
- satributes: Satributes,
- icons: Icons,
- displayNames: string[],
- totalCount: number,
-) => {
- const attribute = satributes[type as MappingKeys];
- if (attribute && attribute.count) {
- displayNames.push(type);
- if (mappingKeysWithIconAndName[type as MappingKeys]) {
- icons[type] = mappingKeysWithIconAndName[type as MappingKeys].icon;
+import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
+import { SimpleHashNftWithIcons, RareSat } from "../../../types/Ordinals";
+
+export function matchCorrespondingIcon(rareSats: SimpleHashNft[]): SimpleHashNftWithIcons[] {
+ return rareSats.map(rareSat => {
+ const iconKeys: string[] = [];
+ if (rareSat.name) {
+ iconKeys.push(rareSat.name.toLowerCase().replace(" ", "_"));
}
- totalCount = attribute.count;
- }
- return { displayNames, totalCount };
-};
-
-export const processSatTypes = (satTypes: string[], satributes: Satributes) => {
- let displayNames: string[] = [];
- let totalCount = 0;
- const icons: { [key: string]: ({ size, color, style }: IconProps) => JSX.Element } = {};
-
- satTypes.forEach(type => {
- const result = processSatType(type, satributes, icons, displayNames, totalCount);
- displayNames = result.displayNames;
- totalCount = result.totalCount;
- });
-
- return { displayNames, totalCount, icons };
-};
-export const processSubrange = (
- subrange: Subrange,
- satributes: Satributes,
- year: string,
- value: number,
-) => {
- const { sat_types } = subrange;
- const { displayNames, totalCount, icons } = processSatTypes(sat_types, satributes);
-
- const name = displayNames
- .map(dn => mappingKeysWithIconAndName[dn.toLowerCase().replace(" ", "_") as MappingKeys]?.name)
- .filter(Boolean)
- .join(" / ");
+ if (rareSat.extra_metadata?.utxo_details?.satributes) {
+ iconKeys.push(...Object.keys(rareSat.extra_metadata.utxo_details.satributes));
+ }
- return {
- count: totalCount.toString() + (totalCount === 1 ? " sat" : " sats"),
- display_name: displayNames.join(" / "),
- year,
- utxo_size: value.toString(),
- icons,
- name,
- };
-};
+ const icons = iconKeys
+ .map(
+ iconKey =>
+ mappingKeysWithIconAndName[iconKey as keyof typeof mappingKeysWithIconAndName]?.icon,
+ )
+ .filter(Boolean) as (({ size, color, style }: IconProps) => JSX.Element)[];
-export const processSatRanges = (satRanges: SatRange[], satributes: Satributes) => {
- return satRanges.flatMap(range => {
- const { year, value, subranges } = range;
- return subranges.flatMap(subrange => processSubrange(subrange, satributes, year, value));
+ return { ...rareSat, icons };
});
-};
-
-export const processRareSat = (sat: Sat) => {
- const { extra_metadata } = sat;
- const satributes = extra_metadata.utxo_details.satributes as Satributes;
- const satRanges = extra_metadata.utxo_details.sat_ranges;
- return processSatRanges(satRanges, satributes);
-};
-
-export const processRareSats = (rareSats: MockedRareSat[]) => {
- return rareSats.flatMap(item => item.nfts.flatMap(processRareSat));
-};
-
-export const groupRareSats = (processedRareSats: RareSat[]) => {
- return processedRareSats.reduce(
- (acc, sat) => {
- if (!acc[sat.utxo_size]) {
- acc[sat.utxo_size] = [];
- }
- acc[sat.utxo_size].push(sat);
- return acc;
- },
- {} as Record,
- );
-};
+}
+
+export function createRareSatObject(
+ rareSats: Record,
+): Record {
+ const result: Record = {};
+
+ for (const [key, value] of Object.entries(rareSats)) {
+ result[key] = value.map(rareSat => {
+ const { icons, extra_metadata } = rareSat;
+ const year = extra_metadata?.utxo_details?.sat_ranges?.[0]?.year || "";
+ const displayed_name =
+ Object.values(extra_metadata?.utxo_details?.satributes || {})
+ .map(attr => attr.display_name)
+ .join(" / ") || "";
+ const utxo_size = extra_metadata?.utxo_details?.sat_ranges?.[0]?.value || "";
+ const name = rareSat.name || "";
+ const count = extra_metadata?.utxo_details?.value || 0;
+ const isMultipleRow = value.length > 1;
+
+ return {
+ year,
+ displayed_name,
+ utxo_size,
+ name,
+ count: `${count} ${count > 1 ? "sats" : "sat"}`,
+ isMultipleRow,
+ icons,
+ };
+ });
+ }
-export const finalizeRareSats = (groupedRareSats: Record) => {
- return Object.entries(groupedRareSats).map(([utxo_size, sats]) => ({
- utxo_size,
- sats,
- isMultipleRow: sats.length > 1,
- }));
-};
+ return result;
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx
index 838d4a0c957f..c9ef9f1f7544 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx
@@ -4,40 +4,57 @@ import TableContainer from "~/renderer/components/TableContainer";
import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader";
import Item from "./Item";
import { TableHeaderTitleKey } from "LLD/features/Collectibles/types/Collection";
-import { Box, Flex } from "@ledgerhq/react-ui";
+import { Box, Flex, InfiniteLoader } from "@ledgerhq/react-ui";
import { TableHeader as TableHeaderContainer } from "./TableHeader";
+import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
+import { Status } from "LLD/features/Collectibles/types/Collectibles";
+import { TanStackStatus } from "../../../types/enum/Collectibles";
-type ViewProps = ReturnType;
+type ViewProps = ReturnType & {
+ status: Status;
+};
+
+type Props = {
+ rareSats: SimpleHashNft[];
+ status: Status;
+};
-function View({ rareSats }: ViewProps) {
+function View({ rareSats, status }: ViewProps) {
+ const isLoading = status === TanStackStatus.Pending;
+ const hasRareSats = Object.values(rareSats).length > 0;
+ console.log("rareSats", rareSats);
return (
+ {isLoading && (
+
+
+
+ )}
- {rareSats
- ? rareSats.map(rareSatGroup => (
-
- {rareSatGroup.sats.map(rareSat => (
-
- ))}
-
- ))
- : null}
- {/** wait for design */}
+ {hasRareSats ? (
+ Object.entries(rareSats).map(([key, rareSatGroup]) => (
+
+ {rareSatGroup.map((rareSat, index) => (
+ - 1} />
+ ))}
+
+ ))
+ ) : (
+
+ {"NOTHING TO SHOW WAITING FOR DESIGN"}
+
+ )}
);
}
-const RareSats = () => {
- return ;
+const RareSats = ({ rareSats, status }: Props) => {
+ return ;
};
export default RareSats;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.ts
index 931c590a56d8..a59b1eafc054 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.ts
@@ -1,12 +1,14 @@
-import { mockedRareSats } from "LLD/features/Collectibles/__integration__/mockedRareSats";
-import { processRareSats, groupRareSats, finalizeRareSats } from "./helpers";
+import { matchCorrespondingIcon, createRareSatObject } from "./helpers";
+import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
+import { regroupRareSatsByContractAddress } from "@ledgerhq/live-nft-react";
-type RareSatsProps = {};
-
-export const useRareSatsModel = (_props: RareSatsProps) => {
- const processedRareSats = processRareSats(mockedRareSats);
- const groupedRareSats = groupRareSats(processedRareSats);
- const finalRareSats = finalizeRareSats(groupedRareSats);
+type Props = {
+ rareSats: SimpleHashNft[];
+};
- return { rareSats: finalRareSats };
+export const useRareSatsModel = ({ rareSats }: Props) => {
+ const matchedRareSats = matchCorrespondingIcon(rareSats);
+ const regroupedRareSats = regroupRareSatsByContractAddress(matchedRareSats);
+ const rareSatsCreated = createRareSatObject(regroupedRareSats);
+ return { rareSats: rareSatsCreated };
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx
index 30aed15cccc5..ab75286de0cc 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx
@@ -1,18 +1,20 @@
import React from "react";
-import { Account } from "@ledgerhq/types-live";
import Inscriptions from "../../components/Inscriptions";
import RareSats from "../../components/RareSats";
import { Flex } from "@ledgerhq/react-ui";
+import useFetchOrdinals from "LLD/features/Collectibles/hooks/useFetchOrdinals";
+import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
type Props = {
- account: Account;
+ account: BitcoinAccount;
};
const OrdinalsAccount: React.FC = ({ account }) => {
+ const { rareSats, status } = useFetchOrdinals({ account });
return (
-
+
);
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/hooks/useFetchOrdinals.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/hooks/useFetchOrdinals.ts
new file mode 100644
index 000000000000..d203e233e420
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/hooks/useFetchOrdinals.ts
@@ -0,0 +1,18 @@
+import { useFetchOrdinals as fetchOrdinalsFromSimpleHash } from "@ledgerhq/live-nft-react";
+import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
+
+type Props = {
+ account: BitcoinAccount;
+};
+
+const useFetchOrdinals = ({ account }: Props) => {
+ const utxosAddresses = account.bitcoinResources?.utxos?.map(utxo => utxo.address).join(",") || "";
+ const { rareSats, inscriptions, status } = fetchOrdinalsFromSimpleHash({
+ addresses: utxosAddresses,
+ threshold: 0,
+ });
+
+ return { rareSats, inscriptions, status };
+};
+
+export default useFetchOrdinals;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collectibles.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collectibles.ts
index aa557daae387..44c7a683017c 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collectibles.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collectibles.ts
@@ -7,3 +7,5 @@ export type BaseNftsProps = {
nfts: (ProtoNFT | NFT)[];
account: Account;
};
+
+export type Status = "error" | "success" | "pending";
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Ordinals.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Ordinals.ts
index 38ce93b53a2a..5e945e5e3b75 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Ordinals.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Ordinals.ts
@@ -1,14 +1,17 @@
+import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
import { mappingKeysWithIconAndName } from "../Ordinals/components/Icons";
import { IconProps } from "./Collection";
export type MappingKeys = keyof typeof mappingKeysWithIconAndName;
-export type RareSat = {
- count: string;
- display_name: string | string[];
+export interface RareSat {
+ displayed_name: string;
+ icons?: (({ size, color, style }: IconProps) => JSX.Element)[];
year: string;
- utxo_size: string;
- icons?: { [key: string]: ({ size, color, style }: IconProps) => JSX.Element };
- name: string;
- isDoubleRow?: boolean;
-};
+ count: string;
+ utxo_size: string | number;
+ isMultipleRow: boolean;
+}
+export interface SimpleHashNftWithIcons extends SimpleHashNft {
+ icons?: (({ size, color, style }: IconProps) => JSX.Element)[];
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/RareSats.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/RareSats.ts
index 0aa47984190e..ad620f3b5af6 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/RareSats.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/RareSats.ts
@@ -52,11 +52,3 @@ export type ExtraMetadata = {
animation_original_url: string | null;
metadata_original_url: string | null;
};
-
-export type Sat = {
- extra_metadata: ExtraMetadata;
-};
-
-export type MockedRareSat = {
- nfts: Sat[];
-};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/Chains.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/Chains.ts
index 35253982236e..461cf1a3d153 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/Chains.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/Chains.ts
@@ -11,3 +11,8 @@ export enum ChainsEnum {
BITCOIN = "bitcoin",
UTXO = "utxo",
}
+
+export enum OrdinalsStandardEnum {
+ INSCRIPTIONS = "inscriptions",
+ RARE_SATS = "raresats",
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/Collectibles.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/Collectibles.ts
index a4c730ef9630..64654ab97cc6 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/Collectibles.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/Collectibles.ts
@@ -2,3 +2,9 @@ export enum CollectibleTypeEnum {
NFT = "NFT",
Ordinal = "Ordinal",
}
+
+export enum TanStackStatus {
+ Error = "error",
+ Success = "success",
+ Pending = "pending",
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/DetailDrawer.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/DetailDrawer.ts
index da05e93321d9..e5bfbe7fbd4b 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/DetailDrawer.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/enum/DetailDrawer.ts
@@ -5,6 +5,7 @@ export enum FieldStatus {
NoData = "nodata",
Queued = "queued",
}
+
export enum ItemType {
Separator = "separator",
ExternalLink = "external",
diff --git a/apps/ledger-live-desktop/src/renderer/screens/account/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/account/index.tsx
index 26c74695c8c6..f5c1b1b850e1 100644
--- a/apps/ledger-live-desktop/src/renderer/screens/account/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/screens/account/index.tsx
@@ -44,6 +44,7 @@ import { useLocalizedUrl } from "~/renderer/hooks/useLocalizedUrls";
import { urls } from "~/config/urls";
import { CurrencyConfig } from "@ledgerhq/coin-framework/config";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
+import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
type Params = {
id: string;
@@ -220,7 +221,7 @@ const AccountPage = ({
)
) : null}
{isOrdinalsEnabled && account.type === "Account" && account.currency.id === "bitcoin" ? (
-
+
) : null}
{account.type === "Account" ? : null}
{
+ if (nft.chain === OrdinalsChainsEnum.INSCRIPTIONS) accumulator.inscriptions.push(nft);
+ else accumulator.rareSats.push(nft);
+ return accumulator;
+ }, initialAccumulator);
+}
+
+/**
+ * Processes an array of rareSats by removing the common rarity.
+ * @param rareSats - An array of rareSats to process.
+ * @returns An array of rareSats with the common rarity removed.
+ */
+export function removeCommonRareSats(rareSats: SimpleHashNft[]): SimpleHashNft[] {
+ return rareSats.filter(nft => {
+ const utxoDetails = nft.extra_metadata?.utxo_details;
+ if (utxoDetails) {
+ const satributes = utxoDetails.satributes;
+ const keys = Object.keys(satributes);
+ if (keys.length === 1 && keys[0] === RareSatRarity.COMMON) {
+ return false;
+ } else {
+ const { common, ...restSatributes } = satributes;
+ return {
+ ...nft,
+ extra_metadata: {
+ ...nft.extra_metadata,
+ utxo_details: {
+ ...utxoDetails,
+ satributes: restSatributes,
+ },
+ },
+ };
+ }
+ }
+ return true;
+ });
+}
+/**
+ * Processes an array of rareSats by regrouping them by Contract Address.
+ * @param rareSats - An array of rareSats to process.
+ * @returns An array of rareSats with the common rarity removed.
+ */
+export function regroupRareSatsByContractAddress(
+ rareSats: SimpleHashNft[],
+): Record {
+ return rareSats.reduce>((acc, sat) => {
+ const { contract_address } = sat;
+ acc[contract_address] = acc[contract_address] || [];
+ acc[contract_address].push(sat);
+ return acc;
+ }, {});
+}
+
+/**
+ * Processes the NFTs by restructuring them.
+ * @param nfts - The array of NFTs to process.
+ * @returns An object containing two arrays: rareSats and inscriptions.
+ */
+export function processOrdinals(nfts: SimpleHashNft[]): {
+ rareSats: SimpleHashNft[];
+ inscriptions: SimpleHashNft[];
+} {
+ const { rareSats, inscriptions } = categorizeNftsByChain(nfts);
+ const rareSatsWithoutCommonSats = removeCommonRareSats(rareSats);
+
+ return {
+ rareSats: rareSatsWithoutCommonSats,
+ inscriptions,
+ };
+}
diff --git a/libs/live-nft-react/src/hooks/types.ts b/libs/live-nft-react/src/hooks/types.ts
index efa0467d75ed..7321a50548be 100644
--- a/libs/live-nft-react/src/hooks/types.ts
+++ b/libs/live-nft-react/src/hooks/types.ts
@@ -50,3 +50,52 @@ export type RefreshMetadataResult = UseMutationResult<
// Check Spam Score Contract or NFT
export type CheckSpamScoreResult = UseQueryResult;
+
+// Fetch Ordinals from SimpleHash
+export enum OrdinalsChainsEnum {
+ RARESATS = "utxo",
+ INSCRIPTIONS = "bitcoin",
+}
+export type OrdinalsStandard = "raresats" | "inscriptions";
+export type FetchNftsProps = {
+ addresses: string;
+ threshold: number;
+};
+export enum RareSatRarity {
+ ALPHA = "alpha",
+ BLACK_EPIC = "black_epic",
+ BLACK_LEGENDARY = "black_legendary",
+ BLACK_MYTHIC = "black_mythic",
+ BLACK_RARE = "black_rare",
+ BLACK_UNCOMMON = "black_uncommon",
+ BLOCK_9 = "block_9",
+ BLOCK_9_450X = "block_9_450x",
+ BLOCK_78 = "block_78",
+ BLOCK_286 = "block_286",
+ BLOCK_666 = "block_666",
+ COMMON = "common",
+ EPIC = "epic",
+ FIRST_TX = "first_tx",
+ HITMAN = "hitman",
+ JPEG = "jpeg",
+ LEGACY = "legacy",
+ LEGENDARY = "legendary",
+ MYTHIC = "mythic",
+ NAKAMOTO = "nakamoto",
+ OMEGA = "omega",
+ PALIBLOCK = "paliblock",
+ PALINDROME = "palindrome",
+ PALINCEPTION = "palinception",
+ PIZZA = "pizza",
+ RARE = "rare",
+ UNCOMMON = "uncommon",
+ VINTAGE = "vintage",
+ LOW_SERIAL_NUMBER = "low_serial_number",
+ SPECIAL_TRANSACTION = "special_transaction",
+ COINBASE_REWARD = "coinbase_reward",
+ DUST = "dust",
+ UNIQUE_PATTERN = "unique_pattern",
+ COLORED_COIN = "colored_coin",
+ HISTORICAL_EVENT = "historical_event",
+ NON_STANDARD_SCRIPT = "non_standard_script",
+}
diff --git a/libs/live-nft-react/src/hooks/useFetchOrdinals.ts b/libs/live-nft-react/src/hooks/useFetchOrdinals.ts
new file mode 100644
index 000000000000..ecee12eb03cd
--- /dev/null
+++ b/libs/live-nft-react/src/hooks/useFetchOrdinals.ts
@@ -0,0 +1,39 @@
+import { fetchNftsFromSimpleHash } from "@ledgerhq/live-nft/api/simplehash";
+import { InfiniteData, useInfiniteQuery, UseInfiniteQueryResult } from "@tanstack/react-query";
+import { SimpleHashResponse, SimpleHashNft } from "@ledgerhq/live-nft/api/types";
+import { FetchNftsProps, OrdinalsChainsEnum } from "./types";
+import { NFTS_QUERY_KEY } from "../queryKeys";
+import { processOrdinals } from "./helpers/ordinals";
+
+type Result = UseInfiniteQueryResult, Error> & {
+ rareSats: SimpleHashNft[];
+ inscriptions: SimpleHashNft[];
+};
+
+export function useFetchOrdinals({ addresses, threshold }: FetchNftsProps): Result {
+ const chains = [OrdinalsChainsEnum.INSCRIPTIONS, OrdinalsChainsEnum.RARESATS];
+ const addressString = Array.isArray(addresses) ? addresses.join(",") : addresses;
+ const queryResult = useInfiniteQuery({
+ queryKey: [NFTS_QUERY_KEY.FetchOrdinals, addresses, chains],
+ queryFn: ({ pageParam }: { pageParam: string | undefined }) =>
+ fetchNftsFromSimpleHash({
+ addresses: addressString,
+ chains,
+ cursor: pageParam,
+ threshold,
+ }),
+ initialPageParam: undefined,
+ getNextPageParam: lastPage => lastPage.next_cursor,
+ enabled: addresses.length > 0,
+ });
+
+ const nfts = queryResult.data?.pages.flatMap(page => page.nfts) ?? [];
+
+ const { rareSats, inscriptions } = processOrdinals(nfts);
+
+ return {
+ ...queryResult,
+ rareSats,
+ inscriptions,
+ };
+}
diff --git a/libs/live-nft-react/src/index.ts b/libs/live-nft-react/src/index.ts
index 3d8c50c23a88..db82f03c1f90 100644
--- a/libs/live-nft-react/src/index.ts
+++ b/libs/live-nft-react/src/index.ts
@@ -4,3 +4,5 @@ export * from "./hooks/useSpamReportNft";
export * from "./hooks/useNftFloorPrice";
export * from "./hooks/useRefreshMetadata";
export * from "./hooks/useCheckSpamScore";
+export * from "./hooks/useFetchOrdinals";
+export * from "./hooks/helpers/ordinals";
diff --git a/libs/live-nft-react/src/queryKeys.ts b/libs/live-nft-react/src/queryKeys.ts
index 9405a157801a..78730a322ce0 100644
--- a/libs/live-nft-react/src/queryKeys.ts
+++ b/libs/live-nft-react/src/queryKeys.ts
@@ -3,4 +3,5 @@ export const NFTS_QUERY_KEY = {
SpamReport: "SpamReport",
FloorPrice: "FloorPrice",
CheckSpamScore: "CheckSpamScore",
+ FetchOrdinals: "FetchOrdinals",
};
diff --git a/libs/live-nft/src/api/types.ts b/libs/live-nft/src/api/types.ts
index e2804a382464..dbcbb2dec051 100644
--- a/libs/live-nft/src/api/types.ts
+++ b/libs/live-nft/src/api/types.ts
@@ -11,6 +11,38 @@ export interface SimpleHashRefreshResponse {
readonly message: string;
}
+export interface UtxoDetails {
+ readonly distinct_rare_sats: number;
+ readonly satributes: {
+ readonly [key: string]: {
+ readonly count: number;
+ readonly display_name: string;
+ readonly description: string;
+ readonly icon: string;
+ };
+ };
+ readonly sat_ranges: {
+ readonly starting_sat: number;
+ readonly value: number;
+ readonly distinct_rare_sats: number;
+ readonly year: string;
+ readonly subranges: {
+ readonly starting_sat: number;
+ readonly value: number;
+ readonly sat_types: string[];
+ }[];
+ }[];
+ readonly block_number: number;
+ readonly value: number;
+ readonly script_pub_key: {
+ readonly asm: string;
+ readonly desc: string;
+ readonly hex: string;
+ readonly address: string;
+ readonly type: string;
+ };
+}
+
export interface SimpleHashNft {
readonly nft_id: string;
readonly chain: string;
@@ -31,6 +63,7 @@ export interface SimpleHashNft {
readonly ledger_metadata?: {
readonly ledger_stax_image: string;
};
+ readonly utxo_details?: UtxoDetails;
readonly image_original_url: string;
readonly animation_original_url: string;
};