Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/recursive inscriptions #4722

Merged
merged 12 commits into from
Dec 19, 2023
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
Loading