Skip to content

Commit

Permalink
Merge pull request #4722 from leather-wallet/release/recursive-inscri…
Browse files Browse the repository at this point in the history
…ptions

Release/recursive inscriptions
  • Loading branch information
pete-watters authored Dec 19, 2023
2 parents 6c1a39d + b713c70 commit 0106d05
Show file tree
Hide file tree
Showing 44 changed files with 414 additions and 145 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
"dependencies": {
"@bitcoinerlab/secp256k1": "1.0.2",
"@coinbase/cbpay-js": "1.0.2",
"@dlc-link/dlc-tools": "1.0.9",
"@dlc-link/dlc-tools": "1.1.1",
"@fungible-systems/zone-file": "2.0.0",
"@hirosystems/token-metadata-api-client": "1.1.0",
"@ledgerhq/hw-transport-webusb": "6.27.19",
Expand Down
11 changes: 8 additions & 3 deletions scripts/generate-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@ const environmentIcons = {
},
};

const devCsp =
"script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; frame-src https://ordinals.com/; frame-ancestors 'none';";

const prodCsp = `default-src 'none'; connect-src *; style-src 'unsafe-inline'; img-src 'self' data: https:; script-src 'self' 'wasm-unsafe-eval'; object-src 'none'; frame-src https://ordinals.com/; frame-ancestors 'none';`;

const contentSecurityPolicyEnvironment = {
development:
"script-src 'self' 'wasm-unsafe-eval'; object-src 'self'; frame-src 'none'; frame-ancestors 'none';",
production: `default-src 'none'; connect-src *; style-src 'unsafe-inline'; img-src 'self' data: https:; script-src 'self' 'wasm-unsafe-eval'; object-src 'none'; frame-src 'none'; frame-ancestors 'none';`,
testing: prodCsp,
development: devCsp,
production: prodCsp,
};

const defaultIconEnvironment = {
Expand Down
24 changes: 17 additions & 7 deletions src/app/common/hooks/use-bitcoin-contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,17 +207,27 @@ export function useBitcoinContracts() {
close();
}

async function getAllSignedBitcoinContracts(): Promise<BitcoinContractListItem[] | undefined> {
async function getAllActiveBitcoinContracts(): Promise<BitcoinContractListItem[] | undefined> {
const bitcoinContractInterface = await getBitcoinContractInterface();

if (!bitcoinContractInterface) return;

await bitcoinContractInterface.periodic_check();
const bitcoinContracts = await bitcoinContractInterface.get_contracts();
const signedBitcoinContracts = bitcoinContracts.filter(
(bitcoinContract: BitcoinContractListItem) => bitcoinContract.state === 'Signed'
);

return signedBitcoinContracts;
const stateOrder = ['Signed', 'Confirmed'];

const activeBitcoinContracts = bitcoinContracts
.filter(
(bitcoinContract: BitcoinContractListItem) =>
bitcoinContract.state === 'Signed' || bitcoinContract.state === 'Confirmed'
)
.sort(
(a: BitcoinContractListItem, b: BitcoinContractListItem) =>
stateOrder.indexOf(a.state) - stateOrder.indexOf(b.state)
);

return activeBitcoinContracts;
}

function getTransactionDetails(txId: string, bitcoinCollateral: number) {
Expand All @@ -239,7 +249,7 @@ export function useBitcoinContracts() {

async function sumBitcoinContractCollateralAmounts(): Promise<Money> {
let bitcoinContractsCollateralSum = 0;
const bitcoinContracts = await getAllSignedBitcoinContracts();
const bitcoinContracts = await getAllActiveBitcoinContracts();
if (!bitcoinContracts) return createMoneyFromDecimal(0, 'BTC');

bitcoinContracts.forEach((bitcoinContract: BitcoinContractListItem) => {
Expand Down Expand Up @@ -313,7 +323,7 @@ export function useBitcoinContracts() {
handleOffer,
handleAccept,
handleReject,
getAllSignedBitcoinContracts,
getAllActiveBitcoinContracts,
sumBitcoinContractCollateralAmounts,
sendRpcResponse,
};
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/brc20-tokens-loader.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {
Brc20Token,
useBrc20TokensQuery,
useGetBrc20TokensQuery,
} from '@app/query/bitcoin/ordinals/brc20/brc20-tokens.query';

interface Brc20TokensLoaderProps {
children(brc20Tokens: Brc20Token[]): React.JSX.Element;
}
export function Brc20TokensLoader({ children }: Brc20TokensLoaderProps) {
const { data: allBrc20TokensResponse } = useBrc20TokensQuery();
const { data: allBrc20TokensResponse } = useGetBrc20TokensQuery();
const brc20Tokens = allBrc20TokensResponse?.pages
.flatMap(page => page.brc20Tokens)
.filter(token => token.length > 0)
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/fees-row/components/fees-row.layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function FeesRowLayout(props: FeesRowLayoutProps) {
const [_, meta] = useField('fee');

return (
<HStack gap="space.04" width="100%" {...rest}>
<HStack gap="space.04" width="100%" {...rest} flexWrap="wrap">
<HStack alignItems="center" justifyContent="space-between" position="relative" width="100%">
<HStack alignItems="center" width="100%">
<Tooltip label={feesInfo} placement="bottom">
Expand All @@ -39,7 +39,7 @@ export function FeesRowLayout(props: FeesRowLayoutProps) {
{feeField}
</HStack>
{isSponsored && <SponsoredLabel />}
{!meta.error && fieldWarning && <WarningLabel>{fieldWarning}</WarningLabel>}
{!meta.error && fieldWarning && <WarningLabel width="100%">{fieldWarning}</WarningLabel>}
</HStack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ReactNode } from 'react';

import { AudioIcon } from '@app/ui/components/icons/audio-icon';

import { CollectibleItemLayout, CollectibleItemLayoutProps } from '../collectible-item.layout';
import { CollectiblePlaceholderLayout } from './collectible-placeholder.layout';

interface CollectibleAudioProps extends Omit<CollectibleItemLayoutProps, 'children'> {
icon: ReactNode;
}
export function CollectibleAudio({ icon, ...props }: CollectibleAudioProps) {
return (
<CollectibleItemLayout collectibleTypeIcon={icon} {...props}>
<CollectiblePlaceholderLayout>
<AudioIcon size="xl" />
</CollectiblePlaceholderLayout>
</CollectibleItemLayout>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ReactNode, useState } from 'react';

import { Iframe } from '@app/ui/components/iframe';

import { CollectibleItemLayout, CollectibleItemLayoutProps } from '../collectible-item.layout';
import { ImageUnavailable } from '../image-unavailable';

interface CollectibleIframeProps extends Omit<CollectibleItemLayoutProps, 'children'> {
icon: ReactNode;
src: string;
}
export function CollectibleIframe({ icon, src, ...props }: CollectibleIframeProps) {
const [isError, setIsError] = useState(false);

if (isError)
return (
<CollectibleItemLayout collectibleTypeIcon={icon} {...props}>
<ImageUnavailable />
</CollectibleItemLayout>
);

return (
<CollectibleItemLayout collectibleTypeIcon={icon} {...props}>
<Iframe
aspectRatio="1 / 1"
height="100%"
objectFit="cover"
onError={() => setIsError(true)}
src={src}
width="100%"
zIndex={99}
/>
</CollectibleItemLayout>
);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useState } from 'react';
import { ReactNode, useState } from 'react';

import { CollectibleItemLayout, CollectibleItemLayoutProps } from '../collectible-item.layout';
import { ImageUnavailable } from '../image-unavailable';

interface CollectibleImageProps extends Omit<CollectibleItemLayoutProps, 'children'> {
alt?: string;
icon: React.JSX.Element;
icon: ReactNode;
src: string;
}
export function CollectibleImage(props: CollectibleImageProps) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Flex } from 'leather-styles/jsx';

import { HasChildren } from '@app/common/has-children';

export function CollectiblePlaceholderLayout({ children }: HasChildren) {
return (
<Flex
alignItems="center"
bg="accent.component-background-default"
flexDirection="column"
height="100%"
justifyContent="center"
textAlign="center"
width="100%"
>
{children}
</Flex>
);
}
39 changes: 31 additions & 8 deletions src/app/features/collectibles/components/bitcoin/inscription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { openInNewTab } from '@app/common/utils/open-in-new-tab';
import { convertInscriptionToSupportedInscriptionType } from '@app/query/bitcoin/ordinals/inscription.hooks';
import { OrdinalIcon } from '@app/ui/components/icons/ordinal-icon';

import { CollectibleAudio } from '../_collectible-types/collectible-audio';
import { CollectibleIframe } from '../_collectible-types/collectible-iframe';
import { CollectibleImage } from '../_collectible-types/collectible-image';
import { CollectibleOther } from '../_collectible-types/collectible-other';
import { InscriptionText } from './inscription-text';
Expand All @@ -26,7 +28,32 @@ export function Inscription({ rawInscription }: InscriptionProps) {
}

switch (inscription.type) {
case 'image': {
case 'audio':
return (
<CollectibleAudio
icon={<OrdinalIcon size="lg" />}
key={inscription.title}
onClickCallToAction={() => openInNewTab(inscription.infoUrl)}
onClickSend={() => openSendInscriptionModal()}
subtitle="Ordinal inscription"
title={`# ${inscription.number}`}
/>
);
case 'html':
case 'svg':
case 'video':
return (
<CollectibleIframe
icon={<OrdinalIcon size="lg" />}
key={inscription.title}
onClickCallToAction={() => openInNewTab(inscription.infoUrl)}
onClickSend={() => openSendInscriptionModal()}
src={inscription.src}
subtitle="Ordinal inscription"
title={`# ${inscription.number}`}
/>
);
case 'image':
return (
<CollectibleImage
icon={<OrdinalIcon size="lg" />}
Expand All @@ -38,8 +65,7 @@ export function Inscription({ rawInscription }: InscriptionProps) {
title={`# ${inscription.number}`}
/>
);
}
case 'text': {
case 'text':
return (
<InscriptionText
contentSrc={inscription.contentSrc}
Expand All @@ -48,8 +74,7 @@ export function Inscription({ rawInscription }: InscriptionProps) {
onClickSend={() => openSendInscriptionModal()}
/>
);
}
case 'other': {
case 'other':
return (
<CollectibleOther
key={inscription.title}
Expand All @@ -61,9 +86,7 @@ export function Inscription({ rawInscription }: InscriptionProps) {
<OrdinalIcon />
</CollectibleOther>
);
}
default: {
default:
return null;
}
}
}
15 changes: 12 additions & 3 deletions src/app/features/collectibles/components/collectible-hover.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { ReactNode } from 'react';

import { Box, styled } from 'leather-styles/jsx';

import { ArrowUpIcon } from '@app/ui/components/icons/arrow-up-icon';

interface CollectibleHoverProps {
collectibleTypeIcon?: React.JSX.Element;
collectibleTypeIcon?: ReactNode;
isHovered: boolean;
onClickCallToAction?(): void;
}
Expand All @@ -24,9 +26,15 @@ export function CollectibleHover({
style={{ opacity: isHovered ? 'inherit' : '0' }}
top="0px"
width="100%"
zIndex={999}
>
<Box bottom="space.03" height="30px" left="space.03" position="absolute" width="30px">
<Box
bottom="space.03"
height="30px"
left="space.03"
position="absolute"
width="30px"
zIndex={999}
>
{collectibleTypeIcon}
</Box>
{onClickCallToAction && (
Expand All @@ -48,6 +56,7 @@ export function CollectibleHover({
top="12px"
type="button"
width="30px"
zIndex={999}
>
<ArrowUpIcon transform="rotate(45deg)" />
</styled.button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface CollectibleItemLayoutProps {
onClickCallToAction?(): void;
onClickLayout?(): void;
onClickSend?(): void;
collectibleTypeIcon?: React.JSX.Element;
collectibleTypeIcon?: ReactNode;
showBorder?: boolean;
subtitle: string;
title: string;
Expand Down
23 changes: 9 additions & 14 deletions src/app/features/collectibles/components/image-unavailable.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import { Flex, styled } from 'leather-styles/jsx';
import { styled } from 'leather-styles/jsx';

import { EyeSlashIcon } from '@app/ui/components/icons/eye-slash-icon';

import { CollectiblePlaceholderLayout } from './_collectible-types/collectible-placeholder.layout';

export function ImageUnavailable() {
return (
<Flex
alignItems="center"
bg="accent.component-background-default"
flexDirection="column"
height="100%"
justifyContent="center"
textAlign="center"
width="100%"
>
<EyeSlashIcon pb="12px" size="md" />
<styled.span textStyle="label.03">Image currently</styled.span>
<styled.span textStyle="label.03">unavailable</styled.span>
</Flex>
<CollectiblePlaceholderLayout>
<EyeSlashIcon size="md" />
<styled.span pt="space.02" px="space.04" textStyle="label.03">
Image currently unavailable
</styled.span>
</CollectiblePlaceholderLayout>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ function areAnyQueriesFetching(...args: number[]) {

export function useIsFetchingCollectiblesRelatedQuery() {
// Ordinal inscriptions
const n1 = useIsFetching([QueryPrefixes.TaprootAddressUtxosMetadata]);
const n2 = useIsFetching([QueryPrefixes.InscriptionFromUtxo]);
const n1 = useIsFetching([QueryPrefixes.TaprootAddressUtxos]);
const n2 = useIsFetching([QueryPrefixes.InscriptionsByAddress]);
const n3 = useIsFetching([QueryPrefixes.InscriptionMetadata]);
const n4 = useIsFetching([QueryPrefixes.OrdinalTextContent]);
const n5 = useIsFetching([QueryPrefixes.InscriptionFromTxid]);
const n5 = useIsFetching([QueryPrefixes.GetInscriptions]);

// BNS
const n6 = useIsFetching([QueryPrefixes.BnsNamesByAddress]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function IncreaseFeeField(props: IncreaseFeeFieldProps): React.JSX.Elemen
onSelectMultiplier={onSelectMultiplier}
/>
<Flex>
<styled.label display="block" fontSize={1} fontWeight={500} mb="space.02" htmlFor="fee">
<styled.label display="block" textStyle="body.02" mb="space.02" htmlFor="fee">
Fee
</styled.label>
<styled.input
Expand Down
2 changes: 0 additions & 2 deletions src/app/features/message-signer/message-preview-box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ export function MessagePreviewBox({ message, hash }: MessageBoxProps) {
<Stack
bg="accent.background-primary"
borderRadius="lg"
fontSize={2}
gap="space.02"
lineHeight="1.6"
px="space.05"
py="space.05"
overflowX="auto"
Expand Down
Loading

0 comments on commit 0106d05

Please sign in to comment.