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

feat: add inscription send flow test #5847

Merged
merged 1 commit into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
"@leather.io/constants": "0.9.2",
"@leather.io/crypto": "1.4.2",
"@leather.io/models": "0.13.0",
"@leather.io/query": "2.8.0",
"@leather.io/query": "2.10.0",
"@leather.io/stacks": "1.0.2",
"@leather.io/tokens": "0.9.0",
"@leather.io/ui": "1.17.1",
Expand Down
50 changes: 42 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors';

import { useGetInscriptionTextContentQuery } from '@leather.io/query';
import { OrdinalAvatarIcon } from '@leather.io/ui';

Expand All @@ -23,6 +25,7 @@ export function InscriptionText({

return (
<CollectibleText
data-testid={SendCryptoAssetSelectors.Inscription}
icon={<OrdinalAvatarIcon size="lg" />}
key={inscriptionNumber}
onClickCallToAction={onClickCallToAction}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ReactNode } from 'react';

import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors';
import { Box, Stack, styled } from 'leather-styles/jsx';
import { token } from 'leather-styles/tokens';
import { useHover } from 'use-events';
Expand All @@ -26,6 +27,7 @@ export function CollectibleItemLayout({
showBorder,
subtitle,
title,
...rest
}: CollectibleItemLayoutProps) {
const [isHovered, bind] = useHover();

Expand All @@ -42,6 +44,7 @@ export function CollectibleItemLayout({
p="space.01"
textAlign="inherit"
width="100%"
{...rest}
{...bind}
>
<Box height="0px" position="relative" pb="100%">
Expand Down Expand Up @@ -88,6 +91,7 @@ export function CollectibleItemLayout({
{onClickSend ? (
<Box p="space.02">
<styled.button
data-testid={SendCryptoAssetSelectors.InscriptionSendButton}
_focus={{ clipPath: 'none', outline: 'focus' }}
_hover={{ bg: 'ink.background-primary' }}
bg="ink.background-primary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,34 +51,42 @@ export function useSendInscriptionForm() {
setIsCheckingFees(true);

try {
// Check tx with lowest fee for errors before routing and
// generating the final transaction with the chosen fee to send
const resp = coverFeeFromAdditionalUtxos(values);

if (!resp) {
setShowError(
'Insufficient funds to cover fee. Deposit some BTC to your Native Segwit address.'
);
return;
}

if (Number(inscription.offset) !== 0) {
setShowError('Sending inscriptions at non-zero offsets is unsupported');
setShowError(FormErrorMessages.NonZeroOffsetInscription);
return;
}

const numInscriptionsOnUtxo = getNumberOfInscriptionOnUtxo(utxo.txid, utxo.vout);
if (numInscriptionsOnUtxo > 1) {
setShowError('Sending inscription from utxo with multiple inscriptions is unsupported');
setShowError(FormErrorMessages.UtxoWithMultipleInscriptions);
return;
}

// Check tx with lowest fee for errors before routing and
// generating the final transaction with the chosen fee to send
const resp = coverFeeFromAdditionalUtxos(values);

if (!resp) {
setShowError(FormErrorMessages.InsufficientFundsToCoverFee);
return;
}

navigate(
`/${RouteUrls.SendOrdinalInscription}/${RouteUrls.SendOrdinalInscriptionChooseFee}`,
{
state: {
inscription,
recipient: values.recipient,
utxo,
backgroundLocation: { pathname: RouteUrls.Home },
},
}
);
} catch (error) {
void analytics.track('ordinals_dot_com_unavailable', { error });

if (error instanceof InsufficientFundsError) {
setShowError(
'Insufficient funds to cover fee. Deposit some BTC to your Native Segwit address.'
);
setShowError(FormErrorMessages.InsufficientFundsToCoverFee);
return;
}

Expand All @@ -90,18 +98,6 @@ export function useSendInscriptionForm() {
} finally {
setIsCheckingFees(false);
}

navigate(
`/${RouteUrls.SendOrdinalInscription}/${RouteUrls.SendOrdinalInscriptionChooseFee}`,
{
state: {
inscription,
recipient: values.recipient,
utxo,
backgroundLocation: { pathname: RouteUrls.Home },
},
}
);
},

async reviewTransaction(
Expand Down
16 changes: 14 additions & 2 deletions src/app/pages/send/ordinal-inscription/send-inscription-form.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useNavigate } from 'react-router-dom';

import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors';
import { Form, Formik } from 'formik';
import { Box, Flex } from 'leather-styles/jsx';

Expand All @@ -8,6 +9,7 @@ import { Button, OrdinalAvatarIcon, Sheet, SheetHeader } from '@leather.io/ui';
import { RouteUrls } from '@shared/route-urls';

import { ErrorLabel } from '@app/components/error-label';
import { TextInputFieldError } from '@app/components/field-error';
import { InscriptionPreview } from '@app/components/inscription-preview-card/components/inscription-preview';
import { InscriptionPreviewCard } from '@app/components/inscription-preview-card/inscription-preview-card';

Expand Down Expand Up @@ -44,7 +46,12 @@ export function SendInscriptionForm() {
isShowing
onClose={() => navigate(RouteUrls.Home)}
footer={
<Button onClick={() => props.handleSubmit()} type="submit" fullWidth>
<Button
data-testid={SendCryptoAssetSelectors.PreviewSendTxBtn}
onClick={() => props.handleSubmit()}
type="submit"
fullWidth
>
Continue
</Button>
}
Expand All @@ -64,9 +71,14 @@ export function SendInscriptionForm() {
label="To"
placeholder="Enter recipient address"
/>
<TextInputFieldError name={recipientFieldName} />
</Flex>
</Box>
{currentError && <ErrorLabel>{currentError}</ErrorLabel>}
{currentError && (
<ErrorLabel data-testid={SendCryptoAssetSelectors.FormFieldInputErrorLabel}>
{currentError}
</ErrorLabel>
)}
</Box>
</SendInscriptionFormLoader>
</Sheet>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useLocation, useNavigate } from 'react-router-dom';

import { bytesToHex } from '@noble/hashes/utils';
import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors';
import { Box, Flex, Stack } from 'leather-styles/jsx';
import get from 'lodash.get';

Expand Down Expand Up @@ -75,6 +76,7 @@ export function SendInscriptionReview() {
onClose={() => navigate(RouteUrls.Home)}
>
<Card
dataTestId={SendCryptoAssetSelectors.ConfirmationDetails}
border="unset"
contentStyle={{
p: 'space.00',
Expand Down Expand Up @@ -109,7 +111,11 @@ export function SendInscriptionReview() {
px="space.06"
>
<Stack width="100%" mb="36px">
<InfoCardRow title="To" value={<FormAddressDisplayer address={recipient} />} />
<InfoCardRow
data-testid={SendCryptoAssetSelectors.ConfirmationDetailsRecipient}
title="To"
value={<FormAddressDisplayer address={recipient} />}
/>
<InfoCardSeparator />
{arrivesIn && <InfoCardRow title="Estimated confirmation time" value={arrivesIn} />}
<InfoCardRow title="Fee" value={feeRowValue} />
Expand Down
4 changes: 4 additions & 0 deletions src/shared/error-messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ export enum FormErrorMessages {
MustSelectAsset = 'Select a valid token to transfer',
SameAddress = 'Cannot send to yourself',
TooMuchPrecision = 'Token can only have {decimals} decimals',

NonZeroOffsetInscription = 'Sending inscriptions at non-zero offsets is unsupported',
UtxoWithMultipleInscriptions = 'Sending inscription from utxo with multiple inscriptions is unsupported',
InsufficientFundsToCoverFee = 'Insufficient funds to cover fee. Deposit some BTC to your Native Segwit address.',
}
9 changes: 9 additions & 0 deletions tests/mocks/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@ export const STANDARD_BIP_FAKE_MNEMONIC =
export const TEST_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS = 'bc1q530dz4h80kwlzywlhx2qn0k6vdtftd93c499yq';
export const TEST_ACCOUNT_1_TAPROOT_ADDRESS =
'bc1putuzj9lyfcm8fef9jpy85nmh33cxuq9u6wyuk536t9kemdk37yjqmkc0pg';
export const TEST_ACCOUNT_2_TAPROOT_ADDRESS =
'bc1pmk2sacpfyy4v5phl8tq6eggu4e8laztep7fsgkkx0nc6m9vydjesaw0g2r';

export const TEST_TESNET_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS =
'tb1q4qgnjewwun2llgken94zqjrx5kpqqycaz5522d';

export const TEST_TESTNET_ACCOUNT_2_BTC_ADDRESS = 'tb1qr8me8t9gu9g6fu926ry5v44yp0wyljrespjtnz';

export const TEST_TESTNET_ACCOUNT_2_TAPROOT_ADDRESS =
'tb1pve00jmp43whpqj2wpcxtc7m8wqhz0azq689y4r7h8tmj8ltaj87qj2nj6w';

// Stacks test addresses
export const TEST_ACCOUNT_1_STX_ADDRESS = 'SPS8CKF63P16J28AYF7PXW9E5AACH0NZNTEFWSFE';
export const TEST_ACCOUNT_2_STX_ADDRESS = 'SPXH3HNBPM5YP15VH16ZXZ9AX6CK289K3MCXRKCB';
Expand Down
27 changes: 27 additions & 0 deletions tests/mocks/mock-inscriptions-bis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Page } from '@playwright/test';

import { BESTINSLOT_API_BASE_URL_TESTNET } from '@leather.io/models';
import { type BestInSlotInscriptionResponse } from '@leather.io/query';

import { TEST_TESTNET_ACCOUNT_2_TAPROOT_ADDRESS } from './constants';

export async function mockTestnetTestAccountInscriptionsRequests(
page: Page,
inscriptions: BestInSlotInscriptionResponse[]
) {
await page.route(`${BESTINSLOT_API_BASE_URL_TESTNET}/wallet/inscriptions_batch`, async route => {
const request = route.request();
const data = request.postData();
const requestBody = data ? JSON.parse(data) : {};

if (requestBody.addresses?.includes(TEST_TESTNET_ACCOUNT_2_TAPROOT_ADDRESS)) {
await route.fulfill({
json: { block_height: 859832, data: inscriptions },
});
return;
}
await route.fulfill({
json: { block_height: 859832, data: [] },
});
});
}
10 changes: 10 additions & 0 deletions tests/mocks/mock-utxos.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Page } from '@playwright/test';

import { BITCOIN_API_BASE_URL_TESTNET } from '@leather.io/models';

import { TEST_ACCOUNT_1_NATIVE_SEGWIT_ADDRESS } from './constants';

export const mockUtxos = [
Expand Down Expand Up @@ -129,3 +131,11 @@ export async function mockMainnetTestAccountBitcoinRequests(page: Page) {
),
]);
}

export async function mockTestnetTestAccountEmptyUtxosRequests(page: Page) {
await page.route(`${BITCOIN_API_BASE_URL_TESTNET}/address/**/utxo`, route =>
route.fulfill({
json: [],
})
);
}
Loading
Loading