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

Add ordinal check when transfering BTC #365

Merged
merged 11 commits into from
May 4, 2023
10 changes: 7 additions & 3 deletions src/app/components/AlertMessage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,29 @@ const Container = styled.div((props) => ({
width: 312,
borderRadius: 12,
zIndex: 16000,
background: props.theme.colors.background.elevation2,
background: props.theme.colors.background.elevation3,
filter: 'drop-shadow(0px 16px 36px rgba(0, 0, 0, 0.5))',
}));

const HeaderText = styled.h1((props) => ({
...props.theme.body_bold_m,
fontSize: 16,
flex: 1,
}));

const DescriptionText = styled.h1((props) => ({
...props.theme.body_m,
color: props.theme.colors.white[200],
margin: 16,
fontSize: 16,
}));

const RowContainer = styled.div((props) => ({
display: 'flex',
flexDirection: 'row',
padding: '20px 16px 16px 16px',
alignItems: 'space-between',
borderBottom: `1px solid ${props.theme.colors.background.elevation3}`,
borderBottom: `1px solid ${props.theme.colors.background.elevation6}`,
}));

const TickMarkButtonContainer = styled.div((props) => ({
Expand Down Expand Up @@ -110,6 +112,7 @@ interface Props {
description: string;
buttonText?: string;
secondButtonText?: string;
isWarningAlert?: boolean;
tickMarkButtonText?: string;
onButtonClick?: () => void;
onSecondButtonClick?: () => void;
Expand All @@ -118,7 +121,7 @@ interface Props {
}

function AlertMessage({
onClose, title, description, buttonText, secondButtonText, tickMarkButtonText, onButtonClick, onSecondButtonClick, tickMarkButtonClick,
onClose, title, description, buttonText, secondButtonText, tickMarkButtonText, isWarningAlert, onButtonClick, onSecondButtonClick, tickMarkButtonClick,
}: Props) {
return (
<>
Expand All @@ -143,6 +146,7 @@ function AlertMessage({
<ActionButton
text={secondButtonText ?? 'Yes'}
onPress={onSecondButtonClick}
warning={isWarningAlert}
/>
</ButtonContainer>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ interface Props {
assetDetail?: string;
isRestoreFundFlow?: boolean;
nonOrdinalUtxos?: BtcUtxoDataResponse [];
amount?: string;
onConfirmClick: (signedTxHex: string) => void;
onCancelClick: () => void;
onBackButtonClick: () => void;
Expand All @@ -129,6 +130,7 @@ function ConfirmBtcTransactionComponent({
assetDetail,
isRestoreFundFlow,
nonOrdinalUtxos,
amount,
onConfirmClick,
onCancelClick,
onBackButtonClick,
Expand Down Expand Up @@ -352,7 +354,7 @@ function ConfirmBtcTransactionComponent({
</Button>
<TransactionSettingAlert
visible={openTransactionSettingModal}
fee={currentFee.toString()}
fee={new BigNumber(currentFee).toString()}
type={ordinalTxUtxo ? 'Ordinals' : 'BTC'}
btcRecipients={recipients}
onApplyClick={onApplyClick}
Expand Down
45 changes: 40 additions & 5 deletions src/app/components/infoContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import styled from 'styled-components';
import InfoIcon from '@assets/img/info.svg';
import WarningIcon from '@assets/img/Warning.svg';

const Container = styled.div<{ type: 'Info' | 'Warning' | undefined }>((props) => ({
interface ContainerProps {
type: 'Info' | 'Warning' | undefined;
showWarningBackground?: boolean;
}
const Container = styled.div<ContainerProps>((props) => ({
display: 'flex',
flexDirection: 'row',
borderRadius: 12,
alignItems: 'flex-start',
backgroundColor: 'transparent',
backgroundColor: props.showWarningBackground ? 'rgba(211, 60, 60, 0.15)' : 'transparent',
padding: props.theme.spacing(8),
marginBottom: props.theme.spacing(6),
border: `1px solid ${
Expand All @@ -26,6 +30,11 @@ const BoldText = styled.h1((props) => ({
color: props.theme.colors.white['0'],
}));

const RedirectText = styled.h1((props) => ({
...props.theme.body_medium_m,
color: props.theme.colors.white['0'],
}));

const SubText = styled.h1((props) => ({
...props.theme.body_xs,
marginTop: props.theme.spacing(2),
Expand All @@ -38,15 +47,34 @@ const Text = styled.h1((props) => ({
lineHeight: 1.4,
}));

const RedirectButton = styled.button((props) => ({
backgroundColor: 'transparent',
color: props.theme.colors.white['0'],
display: 'flex',
marginTop: 4,
justifyContent: 'flex-start',
alignItems: 'flex-start',
}));

interface Props {
titleText?: string;
bodyText: string;
type?: 'Info' | 'Warning';
onClick?: () => void;
redirectText?: string;
showWarningBackground?: boolean;
}

function InfoContainer({ titleText, bodyText, type }: Props) {
function InfoContainer({
titleText,
bodyText,
type,
redirectText,
onClick,
showWarningBackground,
}: Props) {
return (
<Container type={type}>
<Container type={type} showWarningBackground={showWarningBackground}>
<img src={type === 'Warning' ? WarningIcon : InfoIcon} alt="alert" />
<TextContainer>
{titleText ? (
Expand All @@ -55,7 +83,14 @@ function InfoContainer({ titleText, bodyText, type }: Props) {
<SubText>{bodyText}</SubText>
</>
) : (
<Text>{bodyText}</Text>
<>
<Text>{bodyText}</Text>
{redirectText && (
<RedirectButton onClick={onClick}>
<RedirectText>{`${redirectText} →`}</RedirectText>
</RedirectButton>
)}
</>
)}
</TextContainer>
</Container>
Expand Down
11 changes: 1 addition & 10 deletions src/app/components/sendForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -438,16 +438,7 @@ function SendForm({
};

const buyCryptoMessage = balance === 0 && (currencyType === 'STX' || currencyType === 'BTC') && (
<BuyCryptoContainer>
<img src={Info} alt="alert" />
<ColumnContainer>
<BuyCryptoText>{t('NO_FUNDS')}</BuyCryptoText>
<BuyCryptoRedirectButton onClick={onBuyClick}>
<BuyCryptoRedirectText>{t('BUY_CRYPTO')}</BuyCryptoRedirectText>
</BuyCryptoRedirectButton>

</ColumnContainer>
</BuyCryptoContainer>
<InfoContainer bodyText={t('NO_FUNDS')} redirectText={t('BUY_CRYPTO')} onClick={onBuyClick} />
);

const checkIfEnableButton = () => {
Expand Down
6 changes: 3 additions & 3 deletions src/app/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,15 @@ const router = createHashRouter([
element: <Setting />,
},
{
path: 'settings/restore-funds',
path: 'restore-funds',
element: <RestoreFunds />,
},
{
path: 'settings/restore-funds/btc',
path: 'recover-btc',
element: <RestoreBtc />,
},
{
path: 'settings/restore-funds/ordinals',
path: 'recover-ordinals',
element: <RestoreOrdinals />,
},
{
Expand Down
68 changes: 59 additions & 9 deletions src/app/screens/confirmBtcTransaction/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import useWalletSelector from '@hooks/useWalletSelector';
import ConfirmBtcTransactionComponent from '@components/confirmBtcTransactionComponent';
import styled from 'styled-components';
import { saveTimeForNonOrdinalTransferTransaction } from '@utils/localStorage';
import InfoContainer from '@components/infoContainer';
import { useTranslation } from 'react-i18next';
import useOrdinalsByAddress from '@hooks/useOrdinalsByAddress';
import useNonOrdinalUtxos from '@hooks/useNonOrdinalUtxo';
import AlertMessage from '@components/alertMessage';
import { Recipient } from '@secretkeylabs/xverse-core/transactions/btc';
import useBtcClient from '@hooks/useBtcClient';

const BottomBarContainer = styled.h1((props) => ({
Expand All @@ -16,11 +22,18 @@ const BottomBarContainer = styled.h1((props) => ({

function ConfirmBtcTransaction() {
const navigate = useNavigate();
const { t } = useTranslation('translation', { keyPrefix: 'CONFIRM_TRANSACTION' });
const { network, ordinalsAddress, btcAddress } = useWalletSelector();
const btcClient = useBtcClient();
const { ordinalsAddress } = useWalletSelector();
const [recipientAddress, setRecipientAddress] = useState('');
const [signedTx, setSignedTx] = useState<string>('');
const [showOrdinalsDetectedAlert, setShowOrdinalsDetectedAlert] = useState(false);
const location = useLocation();
const { refetch } = useBtcWalletData();
const {
ordinals: ordinalsInBtc,
} = useOrdinalsByAddress(btcAddress);
const { unspentUtxos: withdrawOridnalsUtxos } = useNonOrdinalUtxos();
const {
fee, amount, signedTxHex, recipient, isRestoreFundFlow, unspentUtxos,
} = location.state;
Expand All @@ -38,9 +51,16 @@ function ConfirmBtcTransaction() {
error: errorBtcOrdinalTransaction,
data: btcOrdinalTxBroadcastData,
mutate: broadcastOrdinalTransaction,
} = useMutation<BtcTransactionBroadcastResponse, Error, { signedTx: string }>(
async ({ signedTx }) => btcClient.sendRawTransaction(signedTx),
);
} = useMutation<BtcTransactionBroadcastResponse, Error, { signedTx: string }>(
async ({ signedTx }) => btcClient.sendRawTransaction(signedTx),
);
const onClick = () => {
navigate('/recover-ordinals');
};

const onContinueButtonClick = () => {
mutate({ signedTx });
};

useEffect(() => {
if (errorBtcOrdinalTransaction) {
Expand Down Expand Up @@ -107,9 +127,10 @@ function ConfirmBtcTransaction() {
const handleOnConfirmClick = (txHex: string) => {
if (isRestoreFundFlow) {
broadcastOrdinalTransaction({ signedTx: txHex });
} else {
mutate({ signedTx: txHex });
}
} else if (ordinalsInBtc && ordinalsInBtc.length > 0) {
setSignedTx(txHex);
setShowOrdinalsDetectedAlert(true);
} else mutate({ signedTx: txHex });
};

const goBackToScreen = () => {
Expand All @@ -124,11 +145,29 @@ function ConfirmBtcTransaction() {
});
}
};

const onClosePress = () => {
setShowOrdinalsDetectedAlert(false);
};

return (
<>
{showOrdinalsDetectedAlert && (
<AlertMessage
title={t('BTC_TRANSFER_DANGER_ALERT_TITLE')}
description={t('BTC_TRANSFER_DANGER_ALERT_DESC')}
buttonText={t('BACK')}
onClose={onClosePress}
secondButtonText={t('CONITNUE')}
onButtonClick={onClosePress}
onSecondButtonClick={onContinueButtonClick}
isWarningAlert
/>
)}

<ConfirmBtcTransactionComponent
fee={fee}
recipients={recipient}
recipients={recipient as Recipient[]}
loadingBroadcastedTx={isLoading}
signedTxHex={signedTxHex}
isRestoreFundFlow={isRestoreFundFlow}
Expand All @@ -137,7 +176,18 @@ function ConfirmBtcTransaction() {
onBackButtonClick={goBackToScreen}
isRestoreFundFlow={isRestoreFundFlow}
nonOrdinalUtxos={unspentUtxos}
/>
amount={amount}
>
{ordinalsInBtc && ordinalsInBtc.length > 0 && (
<InfoContainer
type="Warning"
showWarningBackground
bodyText={t('ORDINAL_DETECTED_WARNING')}
redirectText={t('ORDINAL_DETECTED_ACTION')}
onClick={onClick}
/>
)}
</ConfirmBtcTransactionComponent>
<BottomBarContainer>
<BottomBar tab="dashboard" />
</BottomBarContainer>
Expand Down
4 changes: 2 additions & 2 deletions src/app/screens/restoreFunds/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ function RestoreFunds() {
};

const handleOnRestoreBtcClick = () => {
navigate('btc', {
navigate('/recover-btc', {
state: {
unspentUtxos,
},
});
};

const handleOnRestoreOridnalClick = () => {
navigate('ordinals');
navigate('/recover-ordinals');
};

return (
Expand Down
2 changes: 1 addition & 1 deletion src/app/screens/restoreFunds/restoreBtc/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function RestoreBtc() {
if (unspentUtxos) {
amount = sumUnspentOutputs(unspentUtxos);
}
const isNoAmount = amount.isEqualTo(0);
const isNoAmount = amount.isEqualTo(0) || !unspentUtxos[0]?.status.confirmed;

const { data: ordinalsFee, isLoading } = useQuery({
queryKey: [`getFee-${ordinalsAddress}`],
Expand Down
2 changes: 1 addition & 1 deletion src/app/screens/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function Setting() {
};

const onRestoreFundClick = () => {
navigate('restore-funds', {
navigate('/restore-funds', {
state: {
unspentUtxos,
},
Expand Down
12 changes: 9 additions & 3 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"MEMO_INFO": "Adding a memo can have an impact on the transaction fee",
"NEXT": "Next",
"NO_FUNDS": "You don’t have any funds to send.",
"BUY_CRYPTO": "Buy crypto",
"BUY_CRYPTO": "Buy crypto",
"MOVE_TO_ASSET_DETAIL": "Back to asset detail",
"ERRORS": {
"ADDRESS_REQUIRED": "Recipient address is required",
Expand Down Expand Up @@ -113,7 +113,13 @@
"PSBT_CANT_SIGN_ERROR_TITLE": "Failed to sign transaction",
"To": "To",
"YOU_WILL_TRANSFER": "You will transfer",
"YOU_WILL_RECEIVE": "You will receive"
"YOU_WILL_RECEIVE": "You will receive",
"ORDINAL_DETECTED_WARNING": "Ordinal inscription detected in transaction. Continuing will cause your ordinal to be transferred away.",
"ORDINAL_DETECTED_ACTION": "Move to my ordinals address",
"BTC_TRANSFER_DANGER_ALERT_TITLE": "Danger",
"BTC_TRANSFER_DANGER_ALERT_DESC": "You are about to make a Bitcoin transfer which contains an ordinal inscription. Once transferred out of the wallet, you will not be able to recover them.",
"CONITNUE": "Continue",
"BACK": "Back"
},
"TX_ERRORS": {
"INSUFFICIENT_BALANCE": "Insufficient balance",
Expand Down Expand Up @@ -285,7 +291,7 @@
"DESCRIPTION": "You have Bitcoin stored in your ordinal address. You can transfer them to your payment address so they can be used for payments and are shown in your balance."
},
"RESTORE_ORDINAL_SCREEN": {
"TITLE": "Restore Oridnals",
"TITLE": "Restore Ordinals",
"BTC": "Bitcoin",
"TRANSFER": "Transfer",
"BACK": "Back",
Expand Down