Skip to content

Commit

Permalink
✨feat(ui): add simplehash calls for ordis
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasWerey committed Sep 10, 2024
1 parent 7f53095 commit 6d95b40
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 8 deletions.
7 changes: 7 additions & 0 deletions .changeset/dry-parents-breathe.md
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ export const processRareSat = (sat: Sat) => {
return processSatRanges(satRanges, satributes);
};

export const processRareSats = (rareSats: MockedRareSat[]) => {
return rareSats.flatMap(item => item.nfts.flatMap(processRareSat));
export const processRareSats = (rareSats: MockedRareSat[]): RareSat[] => {
return rareSats.flatMap(item =>
item.nfts.flatMap(processRareSat).filter(rareSat => rareSat.display_name !== "common"),
);
};

export const groupRareSats = (processedRareSats: RareSat[]) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function View({ rareSats }: ViewProps) {
}

const RareSats = () => {
return <View {...useRareSatsModel({})} />;
return <View {...useRareSatsModel()} />;
};

export default RareSats;
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { mockedRareSats } from "LLD/features/Collectibles/__integration__/mockedRareSats";
import { processRareSats, groupRareSats, finalizeRareSats } from "./helpers";

type RareSatsProps = {};
//type RareSatsProps = {};

export const useRareSatsModel = (_props: RareSatsProps) => {
export const useRareSatsModel = () => {
const processedRareSats = processRareSats(mockedRareSats);
const groupedRareSats = groupRareSats(processedRareSats);
const finalRareSats = finalizeRareSats(groupedRareSats);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
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<Props> = ({ account }) => {
const { rareSats, inscriptions, status } = useFetchOrdinals({ account });
console.log("fetchOrdinalsFromSimpleHash", inscriptions, rareSats, status);
return (
<Flex mb={50} width="100%" flexDirection="column" rowGap={40}>
<Inscriptions account={account} />
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ export enum ChainsEnum {
BITCOIN = "bitcoin",
UTXO = "utxo",
}

export enum OrdinalsStandardEnum {
INSCRIPTIONS = "inscriptions",
RARE_SATS = "raresats",
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -220,7 +221,7 @@ const AccountPage = ({
)
) : null}
{isOrdinalsEnabled && account.type === "Account" && account.currency.id === "bitcoin" ? (
<OrdinalsAccount account={account} />
<OrdinalsAccount account={account as BitcoinAccount} />
) : null}
{account.type === "Account" ? <TokensList account={account} /> : null}
<OperationsList
Expand Down
68 changes: 68 additions & 0 deletions libs/live-nft-react/src/hooks/helpers/ordinals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
import { OrdinalsChainsEnum, RareSatRarity } from "../types";

/**
* Categorizes an array of NFTs into two categories: rareSats and inscriptions.
* @param nfts - The array of NFTs to categorize.
* @returns An object containing two arrays: rareSats and inscriptions.
*/
export function categorizeNftsByChain(nfts: SimpleHashNft[]): {
rareSats: SimpleHashNft[];
inscriptions: SimpleHashNft[];
} {
const initialAccumulator = {
rareSats: [] as SimpleHashNft[],
inscriptions: [] as SimpleHashNft[],
};

return nfts.reduce((accumulator, nft) => {
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(rareSat => rareSat.name !== RareSatRarity.COMMON);
}

/**
* 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<string, SimpleHashNft[]> {
return rareSats.reduce<Record<string, SimpleHashNft[]>>((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: Record<string, SimpleHashNft[]>;
inscriptions: SimpleHashNft[];
} {
const { rareSats, inscriptions } = categorizeNftsByChain(nfts);
const rareSatsWithoutCommonSats = removeCommonRareSats(rareSats);
const regroupedRareSats = regroupRareSatsByContractAddress(rareSatsWithoutCommonSats);

return {
rareSats: regroupedRareSats,
inscriptions,
};
}
49 changes: 49 additions & 0 deletions libs/live-nft-react/src/hooks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,52 @@ export type RefreshMetadataResult = UseMutationResult<

// Check Spam Score Contract or NFT
export type CheckSpamScoreResult = UseQueryResult<SimpleHashResponse, Error>;

// 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",
}
39 changes: 39 additions & 0 deletions libs/live-nft-react/src/hooks/useFetchOrdinals.ts
Original file line number Diff line number Diff line change
@@ -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<InfiniteData<SimpleHashResponse, unknown>, Error> & {
rareSats: Record<string, SimpleHashNft[]>;
inscriptions: SimpleHashNft[];
};

export function useFetchOrdinals({ addresses, threshold }: FetchNftsProps): Result {
const chains = [OrdinalsChainsEnum.INSCRIPTIONS, OrdinalsChainsEnum.RARESATS];
const addressesString = Array.isArray(addresses) ? addresses.join(",") : addresses;
const queryResult = useInfiniteQuery({
queryKey: [NFTS_QUERY_KEY.FetchOrdinals, addresses, chains],
queryFn: ({ pageParam }: { pageParam: string | undefined }) =>
fetchNftsFromSimpleHash({
addresses: addressesString,
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,
};
}
1 change: 1 addition & 0 deletions libs/live-nft-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from "./hooks/useSpamReportNft";
export * from "./hooks/useNftFloorPrice";
export * from "./hooks/useRefreshMetadata";
export * from "./hooks/useCheckSpamScore";
export * from "./hooks/useFetchOrdinals";
1 change: 1 addition & 0 deletions libs/live-nft-react/src/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export const NFTS_QUERY_KEY = {
SpamReport: "SpamReport",
FloorPrice: "FloorPrice",
CheckSpamScore: "CheckSpamScore",
FetchOrdinals: "FetchOrdinals",
};
33 changes: 33 additions & 0 deletions libs/live-nft/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};
Expand Down

0 comments on commit 6d95b40

Please sign in to comment.