diff --git a/.changeset/friendly-rings-laugh.md b/.changeset/friendly-rings-laugh.md new file mode 100644 index 000000000000..29b1876f67a9 --- /dev/null +++ b/.changeset/friendly-rings-laugh.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +add the ui of rare sats table for ordinals diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Icons.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Icons.tsx index 55cb97100043..feb7ec041fe5 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Icons.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Icons.tsx @@ -1,33 +1,73 @@ import React from "react"; import { Icons } from "@ledgerhq/react-ui"; +import { IconProps } from "../../types/Collection"; export const mappingKeysWithIconAndName = { - alpha: { icon: , name: "Alpha" }, - black_epic: { icon: , name: "Black Epic" }, - black_legendary: { icon: , name: "Black Legendary" }, - black_mythic: { icon: , name: "Black Mythic" }, - black_rare: { icon: , name: "Black Rare" }, - black_uncommon: { icon: , name: "Black Uncommon" }, - block_9: { icon: , name: "Block 9" }, - block_9_450x: { icon: , name: "Block 9 450x" }, - block_78: { icon: , name: "Block 78" }, - block_286: { icon: , name: "Block 286" }, - block_666: { icon: , name: "Block 666" }, - common: { icon: , name: "Common" }, - epic: { icon: , name: "Epic" }, - first_tx: { icon: , name: "First Transaction" }, - hitman: { icon: , name: "Hitman" }, - jpeg: { icon: , name: "JPEG" }, - legacy: { icon: , name: "Legacy" }, - legendary: { icon: , name: "Legendary" }, - mythic: { icon: , name: "Mythic" }, - nakamoto: { icon: , name: "Nakamoto" }, - omega: { icon: , name: "Omega" }, - paliblock: { icon: , name: "PaliBlock Palindrome" }, - palindrome: { icon: , name: "Palindrome" }, - palinception: { icon: , name: "Palinception" }, - pizza: { icon: , name: "Pizza" }, - rare: { icon: , name: "Rare" }, - uncommon: { icon: , name: "Uncommon" }, - vintage: { icon: , name: "Vintage" }, + alpha: { icon: (props: IconProps) => , name: "Alpha" }, + black_epic: { + icon: (props: IconProps) => , + name: "Black Epic", + }, + black_legendary: { + icon: (props: IconProps) => , + name: "Black Legendary", + }, + black_mythic: { + icon: (props: IconProps) => , + name: "Black Mythic", + }, + black_rare: { + icon: (props: IconProps) => , + name: "Black Rare", + }, + black_uncommon: { + icon: (props: IconProps) => , + name: "Black Uncommon", + }, + block_9: { icon: (props: IconProps) => , name: "Block 9" }, + block_9_450x: { + icon: (props: IconProps) => , + name: "Block 9 450x", + }, + block_78: { icon: (props: IconProps) => , name: "Block 78" }, + block_286: { + icon: (props: IconProps) => , + name: "Block 286", + }, + block_666: { + icon: (props: IconProps) => , + name: "Block 666", + }, + common: { icon: (props: IconProps) => , name: "Common" }, + epic: { icon: (props: IconProps) => , name: "Epic" }, + first_tx: { + icon: (props: IconProps) => , + name: "First Transaction", + }, + hitman: { icon: (props: IconProps) => , name: "Hitman" }, + jpeg: { icon: (props: IconProps) => , name: "JPEG" }, + legacy: { icon: (props: IconProps) => , name: "Legacy" }, + legendary: { + icon: (props: IconProps) => , + name: "Legendary", + }, + mythic: { icon: (props: IconProps) => , name: "Mythic" }, + nakamoto: { icon: (props: IconProps) => , name: "Nakamoto" }, + omega: { icon: (props: IconProps) => , name: "Omega" }, + paliblock: { + icon: (props: IconProps) => , + name: "PaliBlock Palindrome", + }, + palindrome: { + icon: (props: IconProps) => , + name: "Palindrome", + }, + palinception: { + icon: (props: IconProps) => , + name: "Palinception", + }, + pizza: { icon: (props: IconProps) => , name: "Pizza" }, + rare: { icon: (props: IconProps) => , name: "Rare" }, + uncommon: { icon: (props: IconProps) => , name: "Uncommon" }, + vintage: { icon: (props: IconProps) => , name: "Vintage" }, }; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/.gitkeep b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/RowLayout.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/RowLayout.tsx new file mode 100644 index 000000000000..b5165d9e9c2f --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/RowLayout.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import { Flex } from "@ledgerhq/react-ui"; +import styled from "styled-components"; + +type Props = { + firstColumnElement: JSX.Element; + secondColumnElement: JSX.Element; + thirdColumnElement?: JSX.Element; + bgColor?: string; + isMultipleRow?: boolean; +}; + +const Container = styled(Flex)` + &:first-child { + border-top: 1px solid ${p => p.theme.colors.palette.text.shade10}; + padding-top: 15px; + } + &:last-child { + padding-bottom: 15px; + } +`; + +const RowLayout: React.FC = ({ + firstColumnElement, + secondColumnElement, + thirdColumnElement, + bgColor, + isMultipleRow, +}) => { + const verticalPadding = isMultipleRow ? 1 : 3; + return ( + + {firstColumnElement} + + + {secondColumnElement} + + + {thirdColumnElement} + + + + ); +}; + +export default RowLayout; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/TableHeader.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/TableHeader.tsx new file mode 100644 index 000000000000..889871442cf8 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/TableHeader.tsx @@ -0,0 +1,35 @@ +import React from "react"; +import { Text } from "@ledgerhq/react-ui"; +import { useTranslation } from "react-i18next"; +import RowLayout from "./RowLayout"; + +export const TableHeader = () => { + const { t } = useTranslation(); + + const firstColumn = ( + + {t("ordinals.rareSats.table.type")} + + ); + + const secondColumn = ( + + {t("ordinals.rareSats.table.year")} + + ); + + const thirdColumn = ( + + {t("ordinals.rareSats.table.utxo")} + + ); + + return ( + + ); +}; 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 new file mode 100644 index 000000000000..c5f460119fd8 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx @@ -0,0 +1,79 @@ +import React from "react"; +import { useRareSatsModel } from "./useRareSatsModel"; +import TableContainer from "~/renderer/components/TableContainer"; +import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader"; +import { TableHeaderTitleKey } from "LLD/features/Collectibles/types/Collection"; +import { Box, Text, Flex } from "@ledgerhq/react-ui"; +import { TableHeader as TableHeaderContainer } from "./TableHeader"; +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"; + +type ViewProps = ReturnType; + +const Item = ({ + icons, + name, + year, + count, + utxo_size, + isMultipleRow, +}: RareSat & { isMultipleRow: boolean }) => { + const firstColumn = ( + + {icons && } + + + ); + const secondColumn = ( + + {year} + + ); + const thirdColumn = ( + + {utxo_size} + + ); + + return ( + + ); +}; + +function View({ rareSats }: ViewProps) { + return ( + + + + + + {rareSats.map((rareSatGroup, index) => ( + + {rareSatGroup.sats.map((rareSat, subIndex) => ( + + ))} + + ))} + + + + ); +} + +const RareSats = () => { + return ; +}; + +export default RareSats; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.tsx new file mode 100644 index 000000000000..bd771fb0d3ba --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.tsx @@ -0,0 +1,122 @@ +import { mockedRareSats } from "LLD/features/Collectibles/__integration__/mockedRareSats"; +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"; + +type RareSatsProps = {}; + +const getIconByKey = (key: string, icons: Icons) => { + if (mappingKeysWithIconAndName[key as MappingKeys]) { + icons[key] = mappingKeysWithIconAndName[key as MappingKeys].icon; + } +}; + +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); + getIconByKey(type, icons); + totalCount = attribute.count; + } + return { displayNames, totalCount }; +}; + +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 }; +}; + +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(" / "); + + return { + count: totalCount.toString() + (totalCount === 1 ? " sat" : " sats"), + display_name: displayNames.join(" / "), + year, + utxo_size: value.toString(), + icons, + name, + }; +}; + +const processSatRanges = (satRanges: SatRange[], satributes: Satributes) => { + return satRanges.flatMap(range => { + const { year, value, subranges } = range; + return subranges.flatMap(subrange => processSubrange(subrange, satributes, year, value)); + }); +}; + +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); +}; + +const processRareSats = (mockedRareSats: MockedRareSat[]) => { + return mockedRareSats.flatMap(item => item.nfts.flatMap(processRareSat)); +}; + +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, + ); +}; + +const finalizeRareSats = (groupedRareSats: Record) => { + return Object.entries(groupedRareSats).map(([utxo_size, sats]) => ({ + utxo_size, + sats, + isMultipleRow: sats.length > 1, + })); +}; + +export const useRareSatsModel = (_props: RareSatsProps) => { + const processedRareSats = processRareSats(mockedRareSats); + const groupedRareSats = groupRareSats(processedRareSats); + const finalRareSats = finalizeRareSats(groupedRareSats); + + return { rareSats: finalRareSats }; +}; 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 d404995e3d08..818ee234694a 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,14 +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"; type Props = { account: Account; }; const OrdinalsAccount: React.FC = ({ account }) => { - return ; - // here we will add the rare sats table + return ( + + + + + ); }; export default OrdinalsAccount; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedRareSats.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedRareSats.ts new file mode 100644 index 000000000000..54665e37d351 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedRareSats.ts @@ -0,0 +1,1846 @@ +// Mock account from Simplehash Docs +export const mockedRareSats = [ + { + next_cursor: null, + next: null, + previous: null, + nfts: [ + { + nft_id: "utxo.7893390614d9a5608e39ea637e5794f7564d3fcdd5ad46105f349c2cf45272fb.1", + chain: "utxo", + contract_address: "7893390614d9a5608e39ea637e5794f7564d3fcdd5ad46105f349c2cf45272fb", + token_id: "1", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-14T11:34:34", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-14T11:34:34", + last_acquired_date: "2024-03-14T11:34:34", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: null, + name: null, + description: null, + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: null, + distinct_nft_count: null, + total_quantity: null, + chains: [], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-14T11:34:34", + block_number: 834655, + transaction: "7893390614d9a5608e39ea637e5794f7564d3fcdd5ad46105f349c2cf45272fb", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 0, + satributes: { + common: { + count: 8000, + display_name: "Common", + description: "Any sat that is not the first sat of its block", + icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png", + }, + }, + sat_ranges: [ + { + starting_sat: 574534229491726, + value: 8000, + distinct_rare_sats: 0, + year: "2011", + subranges: [ + { + starting_sat: 574534229491726, + value: 8000, + sat_types: ["common"], + }, + ], + }, + ], + block_number: 834655, + value: 8000, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.7893390614d9a5608e39ea637e5794f7564d3fcdd5ad46105f349c2cf45272fb.0", + chain: "utxo", + contract_address: "7893390614d9a5608e39ea637e5794f7564d3fcdd5ad46105f349c2cf45272fb", + token_id: "0", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-14T11:34:34", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-14T11:34:34", + last_acquired_date: "2024-03-14T11:34:34", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: null, + name: null, + description: null, + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: null, + distinct_nft_count: null, + total_quantity: null, + chains: [], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-14T11:34:34", + block_number: 834655, + transaction: "7893390614d9a5608e39ea637e5794f7564d3fcdd5ad46105f349c2cf45272fb", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 0, + satributes: { + common: { + count: 9000, + display_name: "Common", + description: "Any sat that is not the first sat of its block", + icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png", + }, + }, + sat_ranges: [ + { + starting_sat: 574534229482726, + value: 9000, + distinct_rare_sats: 0, + year: "2011", + subranges: [ + { + starting_sat: 574534229482726, + value: 9000, + sat_types: ["common"], + }, + ], + }, + ], + block_number: 834655, + value: 9000, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.51fb634f0fefa3441e1a60090d9e292ce1f0803258c2dae818410db4192c89f6.0", + chain: "utxo", + contract_address: "51fb634f0fefa3441e1a60090d9e292ce1f0803258c2dae818410db4192c89f6", + token_id: "0", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-08T10:37:28", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-08T10:37:28", + last_acquired_date: "2024-03-08T10:37:28", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: null, + name: null, + description: null, + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: null, + distinct_nft_count: null, + total_quantity: null, + chains: [], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-08T10:37:28", + block_number: 833719, + transaction: "51fb634f0fefa3441e1a60090d9e292ce1f0803258c2dae818410db4192c89f6", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 0, + satributes: { + common: { + count: 600, + display_name: "Common", + description: "Any sat that is not the first sat of its block", + icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png", + }, + }, + sat_ranges: [ + { + starting_sat: 1032093336971063, + value: 600, + distinct_rare_sats: 0, + year: "2012", + subranges: [ + { + starting_sat: 1032093336971063, + value: 600, + sat_types: ["common"], + }, + ], + }, + ], + block_number: 833719, + value: 600, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.b2011509f56ca83378d5e72e413ed5c939cfa4ff3d82680c1b12b5a6b406ac95.0", + chain: "utxo", + contract_address: "b2011509f56ca83378d5e72e413ed5c939cfa4ff3d82680c1b12b5a6b406ac95", + token_id: "0", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-08T10:33:01", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-08T10:33:01", + last_acquired_date: "2024-03-08T10:33:01", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: null, + name: null, + description: null, + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: null, + distinct_nft_count: null, + total_quantity: null, + chains: [], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-08T10:33:01", + block_number: 833718, + transaction: "b2011509f56ca83378d5e72e413ed5c939cfa4ff3d82680c1b12b5a6b406ac95", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 0, + satributes: { + common: { + count: 600, + display_name: "Common", + description: "Any sat that is not the first sat of its block", + icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png", + }, + }, + sat_ranges: [ + { + starting_sat: 1032093336949888, + value: 600, + distinct_rare_sats: 0, + year: "2012", + subranges: [ + { + starting_sat: 1032093336949888, + value: 600, + sat_types: ["common"], + }, + ], + }, + ], + block_number: 833718, + value: 600, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.398901189471c069dd74068a2884e02829c831432e705b28a0c337696e681b97.0", + chain: "utxo", + contract_address: "398901189471c069dd74068a2884e02829c831432e705b28a0c337696e681b97", + token_id: "0", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-08T10:06:46", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-08T10:06:46", + last_acquired_date: "2024-03-08T10:06:46", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: null, + name: null, + description: null, + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: null, + distinct_nft_count: null, + total_quantity: null, + chains: [], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-08T10:06:46", + block_number: 833714, + transaction: "398901189471c069dd74068a2884e02829c831432e705b28a0c337696e681b97", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 0, + satributes: { + common: { + count: 600, + display_name: "Common", + description: "Any sat that is not the first sat of its block", + icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png", + }, + }, + sat_ranges: [ + { + starting_sat: 1032093336943299, + value: 600, + distinct_rare_sats: 0, + year: "2012", + subranges: [ + { + starting_sat: 1032093336943299, + value: 600, + sat_types: ["common"], + }, + ], + }, + ], + block_number: 833714, + value: 600, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.5", + chain: "utxo", + contract_address: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + token_id: "5", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-08T09:47:36", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-08T09:47:36", + last_acquired_date: "2024-03-08T09:47:36", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: "0123456789abcdeffedcba9876543210", + name: "Rare Sats", + description: + 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.', + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: 5284108, + distinct_nft_count: 7259220, + total_quantity: 7259196, + chains: ["utxo"], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-08T09:47:36", + block_number: 833711, + transaction: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 330, + satributes: { + block_78: { + count: 330, + display_name: "Block 78", + description: + "Sats mined by Hal Finney in block 78 which was the first block mined by someone other than Satoshi", + icon: "https://cdn.simplehash.com/rare_sats/satribute_block78.png", + }, + vintage: { + count: 330, + display_name: "Vintage", + description: "Sats mined in the first 1,000 blocks", + icon: "https://cdn.simplehash.com/rare_sats/satribute_vintage.png", + }, + }, + sat_ranges: [ + { + starting_sat: 392582274563, + value: 330, + distinct_rare_sats: 330, + year: "2009", + subranges: [ + { + starting_sat: 392582274563, + value: 330, + sat_types: ["block_78", "vintage"], + }, + ], + }, + ], + block_number: 833711, + value: 330, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.4", + chain: "utxo", + contract_address: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + token_id: "4", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-08T09:47:36", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-08T09:47:36", + last_acquired_date: "2024-03-08T09:47:36", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: "0123456789abcdeffedcba9876543210", + name: "Rare Sats", + description: + 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.', + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: 5284108, + distinct_nft_count: 7259220, + total_quantity: 7259196, + chains: ["utxo"], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-08T09:47:36", + block_number: 833711, + transaction: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 330, + satributes: { + vintage: { + count: 330, + display_name: "Vintage", + description: "Sats mined in the first 1,000 blocks", + icon: "https://cdn.simplehash.com/rare_sats/satribute_vintage.png", + }, + }, + sat_ranges: [ + { + starting_sat: 4834087454144, + value: 330, + distinct_rare_sats: 330, + year: "2009", + subranges: [ + { + starting_sat: 4834087454144, + value: 330, + sat_types: ["vintage"], + }, + ], + }, + ], + block_number: 833711, + value: 330, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.3", + chain: "utxo", + contract_address: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + token_id: "3", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-08T09:47:36", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-08T09:47:36", + last_acquired_date: "2024-03-08T09:47:36", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: "0123456789abcdeffedcba9876543210", + name: "Rare Sats", + description: + 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.', + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: 5284108, + distinct_nft_count: 7259220, + total_quantity: 7259196, + chains: ["utxo"], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-08T09:47:36", + block_number: 833711, + transaction: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 330, + satributes: { + pizza: { + count: 330, + display_name: "Pizza", + description: + "Sat from the 10,000 Bitcoins used to purchase two Papa John's pizzas on May 22, 2010", + icon: "https://cdn.simplehash.com/rare_sats/satribute_pizza.png", + }, + }, + sat_ranges: [ + { + starting_sat: 265675444186667, + value: 330, + distinct_rare_sats: 330, + year: "2010", + subranges: [ + { + starting_sat: 265675444186667, + value: 330, + sat_types: ["pizza"], + }, + ], + }, + ], + block_number: 833711, + value: 330, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.2", + chain: "utxo", + contract_address: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + token_id: "2", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-08T09:47:36", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-08T09:47:36", + last_acquired_date: "2024-03-08T09:47:36", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: "0123456789abcdeffedcba9876543210", + name: "Rare Sats", + description: + 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.', + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: 5284108, + distinct_nft_count: 7259220, + total_quantity: 7259196, + chains: ["utxo"], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-08T09:47:36", + block_number: 833711, + transaction: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 547, + satributes: { + jpeg: { + count: 547, + display_name: "JPEG", + description: + "Sats involved in the possible first bitcoin trade for an image on February 24, 2010", + icon: "https://cdn.simplehash.com/rare_sats/satribute_jpeg.png", + }, + }, + sat_ranges: [ + { + starting_sat: 152060443363905, + value: 547, + distinct_rare_sats: 547, + year: "2009", + subranges: [ + { + starting_sat: 152060443363905, + value: 547, + sat_types: ["jpeg"], + }, + ], + }, + ], + block_number: 833711, + value: 547, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.1", + chain: "utxo", + contract_address: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + token_id: "1", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2024-03-08T09:47:36", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2024-03-08T09:47:36", + last_acquired_date: "2024-03-08T09:47:36", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: "0123456789abcdeffedcba9876543210", + name: "Rare Sats", + description: + 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.', + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: 5284108, + distinct_nft_count: 7259220, + total_quantity: 7259196, + chains: ["utxo"], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2024-03-08T09:47:36", + block_number: 833711, + transaction: "68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 555, + satributes: { + nakamoto: { + count: 555, + display_name: "Nakamoto", + description: "Sat mined by Satoshi Nakamoto", + icon: "https://cdn.simplehash.com/rare_sats/satribute_nakamoto.png", + }, + }, + sat_ranges: [ + { + starting_sat: 95469010861290, + value: 555, + distinct_rare_sats: 555, + year: "2009", + subranges: [ + { + starting_sat: 95469010861290, + value: 555, + sat_types: ["nakamoto"], + }, + ], + }, + ], + block_number: 833711, + value: 555, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.ce4b148f42e96e30110e666952aeeff6b66a491f7534066076197ff04030318c.1", + chain: "utxo", + contract_address: "ce4b148f42e96e30110e666952aeeff6b66a491f7534066076197ff04030318c", + token_id: "1", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2023-12-11T22:53:55", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2023-12-11T22:53:55", + last_acquired_date: "2023-12-11T22:53:55", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: "0123456789abcdeffedcba9876543210", + name: "Rare Sats", + description: + 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.', + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: 5284108, + distinct_nft_count: 7259220, + total_quantity: 7259196, + chains: ["utxo"], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2023-12-11T22:53:55", + block_number: 820769, + transaction: "ce4b148f42e96e30110e666952aeeff6b66a491f7534066076197ff04030318c", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 835, + satributes: { + pizza: { + count: 835, + display_name: "Pizza", + description: + "Sat from the 10,000 Bitcoins used to purchase two Papa John's pizzas on May 22, 2010", + icon: "https://cdn.simplehash.com/rare_sats/satribute_pizza.png", + }, + }, + sat_ranges: [ + { + starting_sat: 157020560807939, + value: 835, + distinct_rare_sats: 835, + year: "2009", + subranges: [ + { + starting_sat: 157020560807939, + value: 835, + sat_types: ["pizza"], + }, + ], + }, + ], + block_number: 820769, + value: 835, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.adca6501891f2cfce159802f6a2fd798460b004924c5aa5c3352cec4dafa30ba.1", + chain: "utxo", + contract_address: "adca6501891f2cfce159802f6a2fd798460b004924c5aa5c3352cec4dafa30ba", + token_id: "1", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2023-12-11T15:39:00", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2023-12-11T15:39:00", + last_acquired_date: "2023-12-11T15:39:00", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: "0123456789abcdeffedcba9876543210", + name: "Rare Sats", + description: + 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.', + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: 5284108, + distinct_nft_count: 7259220, + total_quantity: 7259196, + chains: ["utxo"], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2023-12-11T15:39:00", + block_number: 820722, + transaction: "adca6501891f2cfce159802f6a2fd798460b004924c5aa5c3352cec4dafa30ba", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 1, + satributes: { + block_9: { + count: 1, + display_name: "Block 9", + description: "Sats mined in block 9 which are the oldest sats in circulation", + icon: "https://cdn.simplehash.com/rare_sats/satribute_block9.png", + }, + first_tx: { + count: 1, + display_name: "First Transaction", + description: + "Sat from the 10 Bitcoins sent from Satashi Nakamoto to Hal Finney in the first Bitcoin transaction ever on January 12, 2009", + icon: "https://cdn.simplehash.com/rare_sats/satribute_first_transaction.png", + }, + nakamoto: { + count: 1, + display_name: "Nakamoto", + description: "Sat mined by Satoshi Nakamoto", + icon: "https://cdn.simplehash.com/rare_sats/satribute_nakamoto.png", + }, + vintage: { + count: 1, + display_name: "Vintage", + description: "Sats mined in the first 1,000 blocks", + icon: "https://cdn.simplehash.com/rare_sats/satribute_vintage.png", + }, + common: { + count: 330, + display_name: "Common", + description: "Any sat that is not the first sat of its block", + icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png", + }, + }, + sat_ranges: [ + { + starting_sat: 45558858287, + value: 1, + distinct_rare_sats: 1, + year: "2009", + subranges: [ + { + starting_sat: 45558858287, + value: 1, + sat_types: ["block_9", "first_tx", "nakamoto", "vintage"], + }, + ], + }, + { + starting_sat: 640648318319738, + value: 330, + distinct_rare_sats: 0, + year: "2011", + subranges: [ + { + starting_sat: 640648318319738, + value: 330, + sat_types: ["common"], + }, + ], + }, + ], + block_number: 820722, + value: 331, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + { + nft_id: "utxo.5e9b99b09f1f259bf2d0afda1ee819abca2de094f8c58c56dd5a5b754f766204.1", + chain: "utxo", + contract_address: "5e9b99b09f1f259bf2d0afda1ee819abca2de094f8c58c56dd5a5b754f766204", + token_id: "1", + name: null, + description: null, + previews: { + image_small_url: null, + image_medium_url: null, + image_large_url: null, + image_opengraph_url: null, + blurhash: null, + predominant_color: null, + }, + image_url: null, + image_properties: null, + video_url: null, + video_properties: null, + audio_url: null, + audio_properties: null, + model_url: null, + model_properties: null, + other_url: null, + other_properties: null, + background_color: null, + external_url: null, + created_date: "2023-12-11T15:00:05", + status: "minted", + token_count: 1, + owner_count: 1, + owners: [ + { + owner_address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + first_acquired_date: "2023-12-11T15:00:05", + last_acquired_date: "2023-12-11T15:00:05", + }, + ], + contract: { + type: "UTXO", + name: null, + symbol: null, + deployed_by: null, + deployed_via_contract: null, + owned_by: null, + has_multiple_collections: false, + }, + collection: { + collection_id: null, + name: null, + description: null, + image_url: null, + image_properties: null, + banner_image_url: null, + category: null, + is_nsfw: null, + external_url: null, + twitter_username: null, + discord_url: null, + instagram_username: null, + medium_username: null, + telegram_url: null, + marketplace_pages: [], + metaplex_mint: null, + metaplex_candy_machine: null, + metaplex_first_verified_creator: null, + spam_score: null, + floor_prices: [], + top_bids: [], + distinct_owner_count: null, + distinct_nft_count: null, + total_quantity: null, + chains: [], + top_contracts: [], + collection_royalties: [], + }, + last_sale: null, + first_created: { + minted_to: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + quantity: 1, + quantity_string: "1", + timestamp: "2023-12-11T15:00:05", + block_number: 820718, + transaction: "5e9b99b09f1f259bf2d0afda1ee819abca2de094f8c58c56dd5a5b754f766204", + transaction_initiator: null, + }, + rarity: { + rank: null, + score: null, + unique_attributes: null, + }, + royalty: [], + extra_metadata: { + attributes: [], + utxo_details: { + distinct_rare_sats: 0, + satributes: { + common: { + count: 10000, + display_name: "Common", + description: "Any sat that is not the first sat of its block", + icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png", + }, + }, + sat_ranges: [ + { + starting_sat: 926537729411206, + value: 546, + distinct_rare_sats: 0, + year: "2012", + subranges: [ + { + starting_sat: 926537729411206, + value: 546, + sat_types: ["common"], + }, + ], + }, + { + starting_sat: 1612575222953082, + value: 9454, + distinct_rare_sats: 0, + year: "2017", + subranges: [ + { + starting_sat: 1612575222953082, + value: 9454, + sat_types: ["common"], + }, + ], + }, + ], + block_number: 820718, + value: 10000, + script_pub_key: { + asm: "1 42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + desc: "rawtr(42fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958)#hh4kgzwr", + hex: "512042fab7cd56eb062af1379a36adf04611b41c6d83ae04179caca9f94821816958", + address: "bc1pgtat0n2kavrz4ufhngm2muzxzx6pcmvr4czp089v48u5sgvpd9vqjsuaql", + type: "witness_v1_taproot", + }, + }, + image_original_url: null, + animation_original_url: null, + metadata_original_url: null, + }, + }, + ], + }, +]; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/IconContainer.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/IconContainer.tsx new file mode 100644 index 000000000000..33ce74431c17 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/IconContainer.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { Flex } from "@ledgerhq/react-ui"; +import { IconProps } from "LLD/features/Collectibles/types/Collection"; + +type Props = { + icons: (({ size, color, style }: IconProps) => JSX.Element)[]; +}; + +const IconContainer: React.FC = ({ icons }) => { + return ( + + {icons.map((Icon, index) => ( + + ))} + + ); +}; + +export default IconContainer; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx index 2ab7c9bef6ce..c5d11986eaf9 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx @@ -6,17 +6,32 @@ type Props = { tokenName: string | string[]; isLoading: boolean; collectionName?: string; + complementaryData?: string; }; -const TokenTitle: React.FC = ({ tokenName, isLoading, collectionName }) => { +const TokenTitle: React.FC = ({ + tokenName, + isLoading, + collectionName, + complementaryData, +}) => { + const isInsideRareSatRow = Boolean(complementaryData); return ( - + {tokenName} - - {collectionName} + + {collectionName || complementaryData} diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx index c930b1f9566e..6c0ef4bf55d2 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx @@ -1,6 +1,6 @@ import React from "react"; import { Media, Skeleton } from "../../index"; -import { Box, Flex, Text } from "@ledgerhq/react-ui"; +import { Box, Text } from "@ledgerhq/react-ui"; import { rgba } from "~/renderer/styles/helpers"; import styled from "styled-components"; import { @@ -10,6 +10,7 @@ import { } from "LLD/features/Collectibles/utils/typeGuardsChecker"; import { RowProps as Props } from "LLD/features/Collectibles/types/Collection"; import TokenTitle from "./TokenTitle"; +import IconContainer from "./IconContainer"; const Container = styled(Box)` &.disabled { @@ -25,13 +26,6 @@ const Container = styled(Box)` } `; -const SatsIconContainer = styled(Flex)` - border-radius: 8px; - background: ${p => p.theme.colors.opacityDefault.c05}; - border: 1px solid ${p => p.theme.colors.opacityDefault.c10}; - padding: 8px; -`; - const TableRow: React.FC = props => { const mediaBox = () => { return ( @@ -53,17 +47,7 @@ const TableRow: React.FC = props => { )} {isOrdinalsRow(props) && props.tokenIcons.length != 0 && ( - - {props.tokenIcons?.map((Icon, index) => ( - - ))} - + )} ); @@ -75,7 +59,6 @@ const TableRow: React.FC = props => { justifyContent="center" px={4} py={3} - maxHeight={64} display={"flex"} onClick={props.onClick} > diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collection.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collection.ts index 4410715c5b7b..c2fd9cf1e8bf 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collection.ts +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Collection.ts @@ -42,6 +42,7 @@ export type TableHeaderActionsProps = { export enum TableHeaderTitleKey { NFTCollections = "NFT.collections.title", Inscriptions = "Inscriptions", + RareSats = "ordinals.rareSats.title", } export type TableHeaderProps = { 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 new file mode 100644 index 000000000000..38ce93b53a2a --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/Ordinals.ts @@ -0,0 +1,14 @@ +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[]; + year: string; + utxo_size: string; + icons?: { [key: string]: ({ size, color, style }: IconProps) => JSX.Element }; + name: string; + isDoubleRow?: boolean; +}; 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 new file mode 100644 index 000000000000..0aa47984190e --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/types/RareSats.ts @@ -0,0 +1,62 @@ +import { IconProps } from "./Collection"; +import { MappingKeys } from "./Ordinals"; + +export type Satributes = { + [key in MappingKeys]?: { + count: number; + display_name: string | string[]; + description?: string; + icon?: string; + }; +}; + +export type Subrange = { + starting_sat: number; + value: number; + sat_types: string[]; +}; + +export type SatRange = { + starting_sat: number; + value: number; + distinct_rare_sats: number; + year: string; + subranges: Subrange[]; +}; + +export type UtxoDetails = { + distinct_rare_sats: number; + satributes: Satributes; + sat_ranges: SatRange[]; + block_number: number; + value: number; + script_pub_key: { + asm: string; + desc: string; + hex: string; + address: string; + type: string; + }; +}; + +export type Icons = Record JSX.Element>; + +export type ExtraMetadata = { + attributes: { + trait_type: string; + value: string; + display_type: string; + }[]; + utxo_details: UtxoDetails; + image_original_url: string | null; + 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/static/i18n/en/app.json b/apps/ledger-live-desktop/static/i18n/en/app.json index 88c6642f74d0..188e7333d73f 100644 --- a/apps/ledger-live-desktop/static/i18n/en/app.json +++ b/apps/ledger-live-desktop/static/i18n/en/app.json @@ -6591,5 +6591,15 @@ "title": "Continue on your Ledger {{wording}}", "description": "Follow the instruction which appear on your Ledger’s Trusted Display." } + }, + "ordinals": { + "rareSats": { + "title": "Rare Sats", + "table": { + "type": "Sat Type / Amount", + "year": "Year", + "utxo": "UTXO size" + } + } } } \ No newline at end of file