Skip to content

Commit

Permalink
feat: working send flow
Browse files Browse the repository at this point in the history
  • Loading branch information
creed-victor committed Dec 20, 2023
1 parent 05cddfb commit 01da390
Show file tree
Hide file tree
Showing 13 changed files with 255 additions and 104 deletions.
4 changes: 3 additions & 1 deletion apps/frontend/src/app/3_organisms/Boltz/Boltz.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const checkSwapStatus = async (id: string) => {

export const streamSwapStatus = async (
id: string,
cb: (status: string) => void,
cb: (status: any) => void,
) => {
const stream = new EventSource(
BOLTZ_URL[defaultChainId] + '/streamswapstatus?id=' + id,
Expand All @@ -51,6 +51,8 @@ export const streamSwapStatus = async (

cb(data.status);
};

return stream;
};

export const swapToBTC = async (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React, { FC, useMemo } from 'react';

import classNames from 'classnames';
import { t } from 'i18next';

import { Icon, IconNames } from '@sovryn/ui';

import { translations } from '../../../../../../locales/i18n';

export enum BoltzStatusType {
invoiceSet = 'invoice.set',
txConfirmed = 'transaction.confirmed',
txPending = 'transaction.pending',
txPaid = 'transaction.paid',
txClaimed = 'transaction.claimed',
// todo: add failed statuses?
}

type BoltzStatusProps = {
status?: BoltzStatusType;
};

export const BoltzStatus: FC<BoltzStatusProps> = ({ status }) => {
const renderStatusMessage = useMemo(() => {
switch (status) {
case BoltzStatusType.invoiceSet:
return t(translations.boltz.send.boltzStatus.invoiceSet);
case BoltzStatusType.txPending:
return t(translations.boltz.send.boltzStatus.txPending);
case BoltzStatusType.txConfirmed:
return t(translations.boltz.send.boltzStatus.txConfirmed);
case BoltzStatusType.txPaid:
return t(translations.boltz.send.boltzStatus.txPaid);
case BoltzStatusType.txClaimed:
return t(translations.boltz.send.boltzStatus.txClaimed);
default:
return status;
}
}, [status]);

return status === undefined ? (
<Icon icon={IconNames.PENDING} />
) : (
<div
className={classNames({
'text-success': [
BoltzStatusType.txPaid,
BoltzStatusType.txClaimed,
].includes(status),
})}
>
{renderStatusMessage}
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import React, {
useState,
} from 'react';

import { BigNumber } from 'ethers';
import { BigNumber, ethers } from 'ethers';
import { t } from 'i18next';

import { StatusType } from '@sovryn/ui';
Expand All @@ -15,15 +15,21 @@ import { useTransactionContext } from '../../../../../../contexts/TransactionCon
import { useAccount } from '../../../../../../hooks/useAccount';
import { useGetProtocolContract } from '../../../../../../hooks/useGetContract';
import { translations } from '../../../../../../locales/i18n';
import { fromWei, toWei } from '../../../../../../utils/math';
import { decimalic, fromWei, toWei } from '../../../../../../utils/math';
import { Swap } from '../../../../Boltz/Boltz.type';
import {
decodeInvoice,
streamSwapStatus,
swapToLighting,
} from '../../../../Boltz/Boltz.utils';
import { TransactionType } from '../../../../TransactionStepDialog/TransactionStepDialog.types';
import { GAS_LIMIT_FAST_BTC_WITHDRAW } from '../../../constants';
import { ReviewScreen } from './ReviewScreen';
import { StatusScreen } from './StatusScreen';
import {
WithdrawBoltzContext,
WithdrawBoltzStep,
} from '../../../contexts/withdraw-boltz-context';
import { BoltzStatusType } from './BoltzStatus';
import { ReviewScreen } from './ReviewScreen';
import { StatusScreen } from './StatusScreen';

type ConfirmationScreensProps = {
onClose: () => void;
Expand All @@ -32,13 +38,15 @@ type ConfirmationScreensProps = {
export const ConfirmationScreens: React.FC<ConfirmationScreensProps> = ({
onClose,
}) => {
const { account } = useAccount();
const { account, signer } = useAccount();
const { step, invoice, amount, set } = useContext(WithdrawBoltzContext);

const { setTransactions, setTitle, setIsOpen } = useTransactionContext();

const [txHash, setTxHash] = useState<string | undefined>(undefined);
const [txStatus, setTxStatus] = useState(StatusType.idle);
const [boltzStatus, setBoltzStatus] = useState<BoltzStatusType>();
const [swapData, setSwapData] = useState<Swap>();
const [currentFeeWei, setCurrentFeeWei] = useState(BigNumber.from(0));

const fastBtcBridgeContract = useGetProtocolContract('fastBtcBridge');
Expand All @@ -57,6 +65,20 @@ export const ConfirmationScreens: React.FC<ConfirmationScreensProps> = ({
getCurrentFeeWei().then();
}, [getCurrentFeeWei]);

useEffect(() => {
if (!swapData) {
return;
}
let event: EventSource;
(async () => {
event = await streamSwapStatus(swapData?.id, setBoltzStatus);
})();

return () => {
event?.close();
};
}, [swapData]);

const feesPaid = useMemo(
() =>
currentFeeWei && currentFeeWei.gt(0) ? Number(fromWei(currentFeeWei)) : 0,
Expand All @@ -76,41 +98,64 @@ export const ConfirmationScreens: React.FC<ConfirmationScreensProps> = ({
);

const handleConfirm = useCallback(async () => {
if (fastBtcBridgeContract) {
setTransactions([
{
title: t(translations.fastBtc.send.txDialog.sendBTC),
request: {
type: TransactionType.signTransaction,
contract: fastBtcBridgeContract,
fnName: 'transferToBtc',
args: [invoice],
value: toWei(amount),
gasLimit: GAS_LIMIT_FAST_BTC_WITHDRAW,
},
onStart: hash => {
setTxHash(hash);
set(prevState => ({
...prevState,
step: WithdrawBoltzStep.CONFIRM,
}));
setIsOpen(false);
},
onChangeStatus: setTxStatus,
},
]);
let swap = swapData;
if (!swapData) {
swap = await swapToLighting(invoice, account);
setSwapData(swap);
}

setTitle(t(translations.fastBtc.send.txDialog.title));
setIsOpen(true);
if (!swap) {
console.error('Swap data is not defined');
return;
}

const value = decimalic(swap.expectedAmount).div(1e8).toBigNumber();

const decoded = decodeInvoice(invoice);
const { preimageHash } = decoded;

const iface = new ethers.utils.Interface([
'function lock(bytes32,address,uint256) payable',
]);
const data = iface.encodeFunctionData('lock', [
'0x' + preimageHash,
swap.claimAddress,
swap.timeoutBlockHeight,
]);

setTransactions([
{
title: t(translations.boltz.send.txDialog.title),
request: {
type: TransactionType.signTransactionData,
signer: signer!,
to: swap.address,
value,
data,
},
onStart: hash => {
setTxHash(hash);
set(prevState => ({
...prevState,
step: WithdrawBoltzStep.CONFIRM,
}));
setIsOpen(false);
},
onChangeStatus: setTxStatus,
},
]);

setTitle(t(translations.fastBtc.send.txDialog.title));
setIsOpen(true);
}, [
swapData,
invoice,
amount,
fastBtcBridgeContract,
set,
setIsOpen,
setTitle,
setTransactions,
signer,
setTitle,
setIsOpen,
account,
set,
]);

const handleRetry = useCallback(() => {
Expand All @@ -127,6 +172,7 @@ export const ConfirmationScreens: React.FC<ConfirmationScreensProps> = ({
from={account}
to={invoice}
amount={amount}
boltzStatus={boltzStatus}
/>
);
}
Expand All @@ -135,6 +181,7 @@ export const ConfirmationScreens: React.FC<ConfirmationScreensProps> = ({
<StatusScreen
txHash={txHash}
txStatus={txStatus}
boltzStatus={boltzStatus}
onClose={onClose}
feesPaid={feesPaid}
receiveAmount={receiveAmount}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ import React, {
useState,
} from 'react';

import {
validate,
getAddressInfo,
AddressType,
} from 'bitcoin-address-validation';
import { t } from 'i18next';

import {
Expand All @@ -26,20 +21,18 @@ import {
ParagraphSize,
} from '@sovryn/ui';

import { useGetProtocolContract } from '../../../../../../hooks/useGetContract';
import {
BITCOIN,
BTC_RENDER_PRECISION,
} from '../../../../../../constants/currencies';
import { useMaintenance } from '../../../../../../hooks/useMaintenance';
import { translations } from '../../../../../../locales/i18n';
import { currentNetwork } from '../../../../../../utils/helpers';
import { decimalic } from '../../../../../../utils/math';
import { decodeInvoice } from '../../../../Boltz/Boltz.utils';
import {
WithdrawBoltzContext,
WithdrawBoltzStep,
} from '../../../contexts/withdraw-boltz-context';
import {
BITCOIN,
BTC_RENDER_PRECISION,
} from '../../../../../../constants/currencies';
import { decodeInvoice } from '../../../../Boltz/Boltz.utils';
import { decimalic } from '../../../../../../utils/math';

enum InvoiceValidationState {
NONE = 'NONE',
Expand Down
Loading

0 comments on commit 01da390

Please sign in to comment.