Skip to content

Commit

Permalink
Merge pull request #365 from secretkeylabs/imamahzafar/ordinal-check
Browse files Browse the repository at this point in the history
Add ordinal check when transfering BTC
  • Loading branch information
yknl committed May 4, 2023
2 parents a870087 + ec3f1a7 commit cf60028
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 38 deletions.
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
4 changes: 3 additions & 1 deletion src/app/components/confirmBtcTransactionComponent/index.tsx
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

0 comments on commit cf60028

Please sign in to comment.