From eef957b12514cfaafa6c5b35572ba656d2c5680d Mon Sep 17 00:00:00 2001 From: Philipp Walter Date: Wed, 11 Dec 2024 16:34:59 +0100 Subject: [PATCH] fix(send): update review screen --- e2e/send.e2e.js | 51 +++-- src/components/Money.tsx | 5 +- .../bottom-sheet/SendNavigation.tsx | 2 +- src/screens/Settings/AddressViewer/index.tsx | 14 +- src/screens/Transfer/ExternalNode/Confirm.tsx | 4 +- src/screens/Wallets/AssetButton.tsx | 11 +- src/screens/Wallets/Send/Address.tsx | 8 +- src/screens/Wallets/Send/Amount.tsx | 15 +- src/screens/Wallets/Send/Error.tsx | 4 +- src/screens/Wallets/Send/ReviewAndSend.tsx | 201 +++++++++--------- src/store/actions/wallet.ts | 2 +- src/store/reselect/ui.ts | 12 +- src/store/shapes/ui.ts | 9 +- src/store/slices/ui.ts | 11 + src/store/types/ui.ts | 15 +- src/store/utils/blocktank.ts | 4 +- src/utils/scanner/scanner.ts | 16 +- src/utils/wallet/transactions.ts | 16 +- src/utils/wallet/transfer.ts | 4 +- 19 files changed, 231 insertions(+), 173 deletions(-) diff --git a/e2e/send.e2e.js b/e2e/send.e2e.js index fd4264d8a..e77bfefef 100644 --- a/e2e/send.e2e.js +++ b/e2e/send.e2e.js @@ -299,10 +299,33 @@ d('Send', () => { .toHaveText('129 502') .withTimeout(10000); - // send to unified invoice w/ amount + // can edit invoice on the review screen const { paymentRequest: invoice2 } = await lnd.addInvoice({ value: 10000 }); + await enterAddress(invoice2); + let attributes = await element( + by.id('ReviewAmount-primary'), + ).getAttributes(); + let amount = attributes.label; + jestExpect(amount).toBe('10 000'); + await element(by.id('ReviewUri')).tap(); + await element(by.id('RecipientInput')).replaceText(onchainAddress); + await element(by.id('RecipientInput')).tapReturnKey(); + await element(by.id('AddressContinue')).tap(); + await expect(element(by.id('AssetButton-savings'))).toBeVisible(); + await element(by.id('N2').withAncestor(by.id('SendAmountNumberPad'))).tap(); + await element( + by.id('N0').withAncestor(by.id('SendAmountNumberPad')), + ).multiTap(4); + await element(by.id('ContinueAmount')).tap(); + attributes = await element(by.id('ReviewAmount-primary')).getAttributes(); + amount = attributes.label; + jestExpect(amount).toBe('20 000'); + await element(by.id('SendSheet')).swipe('down'); + + // send to unified invoice w/ amount + const { paymentRequest: invoice3 } = await lnd.addInvoice({ value: 10000 }); const unified1 = encode(onchainAddress, { - lightning: invoice2, + lightning: invoice3, amount: 10000, }); @@ -319,11 +342,11 @@ d('Send', () => { .withTimeout(10000); // send to unified invoice w/ amount exceeding balance(s) - const { paymentRequest: invoice3 } = await lnd.addInvoice({ + const { paymentRequest: invoice4 } = await lnd.addInvoice({ value: 200000, }); const unified2 = encode(onchainAddress, { - lightning: invoice3, + lightning: invoice4, amount: 200000, }); @@ -369,8 +392,8 @@ d('Send', () => { .withTimeout(10000); // send to unified invoice w/o amount (lightning) - const { paymentRequest: invoice4 } = await lnd.addInvoice(); - const unified4 = encode(onchainAddress, { lightning: invoice4 }); + const { paymentRequest: invoice5 } = await lnd.addInvoice(); + const unified4 = encode(onchainAddress, { lightning: invoice5 }); await enterAddress(unified4); // max amount (lightning) @@ -396,8 +419,8 @@ d('Send', () => { .withTimeout(10000); // send to unified invoice w/o amount (switch to onchain) - const { paymentRequest: invoice5 } = await lnd.addInvoice(); - const unified5 = encode(onchainAddress, { lightning: invoice5 }); + const { paymentRequest: invoice6 } = await lnd.addInvoice(); + const unified5 = encode(onchainAddress, { lightning: invoice6 }); await enterAddress(unified5); @@ -434,7 +457,7 @@ d('Send', () => { .withTimeout(10000); // send to lightning invoice w/ amount (quickpay) - const { paymentRequest: invoice6 } = await lnd.addInvoice({ value: 1000 }); + const { paymentRequest: invoice7 } = await lnd.addInvoice({ value: 1000 }); // enable quickpay await element(by.id('Settings')).tap(); @@ -444,7 +467,7 @@ d('Send', () => { await element(by.id('QuickpayToggle')).tap(); await element(by.id('NavigationClose')).tap(); - await enterAddress(invoice6); + await enterAddress(invoice7); await waitFor(element(by.id('SendSuccess'))) .toBeVisible() .withTimeout(10000); @@ -456,9 +479,9 @@ d('Send', () => { .withTimeout(10000); // send to unified invoice w/ amount (quickpay) - const { paymentRequest: invoice7 } = await lnd.addInvoice({ value: 1000 }); + const { paymentRequest: invoice8 } = await lnd.addInvoice({ value: 1000 }); const unified7 = encode(onchainAddress, { - lightning: invoice7, + lightning: invoice8, amount: 1000, }); @@ -474,8 +497,8 @@ d('Send', () => { .withTimeout(10000); // send to lightning invoice w/ amount (skip quickpay for large amounts) - const { paymentRequest: invoice8 } = await lnd.addInvoice({ value: 10000 }); - await enterAddress(invoice8); + const { paymentRequest: invoice9 } = await lnd.addInvoice({ value: 10000 }); + await enterAddress(invoice9); await expect(element(by.id('ReviewAmount'))).toBeVisible(); await element(by.id('SendSheet')).swipe('down'); diff --git a/src/components/Money.tsx b/src/components/Money.tsx index 9c4681a50..c7376a557 100644 --- a/src/components/Money.tsx +++ b/src/components/Money.tsx @@ -133,7 +133,10 @@ const Money = (props: MoneyProps): ReactElement => { } return ( - + {sign && ( void }; Recipient: undefined; Contacts: undefined; - Address: undefined; + Address: { uri?: string } | undefined; Scanner: undefined; Amount: undefined; CoinSelection: undefined; diff --git a/src/screens/Settings/AddressViewer/index.tsx b/src/screens/Settings/AddressViewer/index.tsx index 69a3d1a13..71e8f631a 100644 --- a/src/screens/Settings/AddressViewer/index.tsx +++ b/src/screens/Settings/AddressViewer/index.tsx @@ -56,9 +56,9 @@ import { updateWallet } from '../../../store/slices/wallet'; import { resetSendTransaction, setupOnChainTransaction, - updateSendTransaction, + updateBeignetSendTransaction, } from '../../../store/actions/wallet'; -import { updateUi } from '../../../store/slices/ui'; +import { updateSendTransaction } from '../../../store/slices/ui'; import { showBottomSheet } from '../../../store/utils/ui'; import SearchInput from '../../../components/SearchInput'; import AddressViewerListItem from './AddressViewerListItem'; @@ -640,11 +640,17 @@ const AddressViewer = ({ if (receiveAddress.isErr()) { return; } - updateSendTransaction({ + updateBeignetSendTransaction({ ...transactionRes.value, outputs: [{ address: receiveAddress.value, value: 0, index: 0 }], }); - dispatch(updateUi({ fromAddressViewer: true })); + dispatch( + updateSendTransaction({ + fromAddressViewer: true, + paymentMethod: 'onchain', + uri: receiveAddress.value, + }), + ); sendMax(); showBottomSheet('sendNavigation', { screen: 'ReviewAndSend' }); }, diff --git a/src/screens/Transfer/ExternalNode/Confirm.tsx b/src/screens/Transfer/ExternalNode/Confirm.tsx index 0b3d39563..5292283fd 100644 --- a/src/screens/Transfer/ExternalNode/Confirm.tsx +++ b/src/screens/Transfer/ExternalNode/Confirm.tsx @@ -18,7 +18,7 @@ import { createFundedChannel } from '../../../utils/wallet/transfer'; import { useAppSelector } from '../../../hooks/redux'; import { TransferScreenProps } from '../../../navigation/types'; import { transactionFeeSelector } from '../../../store/reselect/wallet'; -import { updateSendTransaction } from '../../../store/actions/wallet'; +import { updateBeignetSendTransaction } from '../../../store/actions/wallet'; const image = require('../../../assets/illustrations/coin-stack-x.png'); @@ -38,7 +38,7 @@ const ExternalConfirm = ({ useCallback(() => { // Using a placeholder address here to enable the FeeCustom screen to function properly. // The actual funding address will be updated later in createFundedChannel. - updateSendTransaction({ + updateBeignetSendTransaction({ outputs: [{ address: 'xxx', value: localBalance, index: 0 }], }); }, [localBalance]), diff --git a/src/screens/Wallets/AssetButton.tsx b/src/screens/Wallets/AssetButton.tsx index def86a856..880deb8cb 100644 --- a/src/screens/Wallets/AssetButton.tsx +++ b/src/screens/Wallets/AssetButton.tsx @@ -7,7 +7,8 @@ import { Caption13Up } from '../../styles/text'; import { SwitchIcon } from '../../styles/icons'; import { useAppDispatch, useAppSelector } from '../../hooks/redux'; import useColors from '../../hooks/colors'; -import { updateUi } from '../../store/slices/ui'; +import { updateSendTransaction } from '../../store/slices/ui'; +import { sendTransactionSelector } from '../../store/reselect/ui'; const AssetButton = ({ style, @@ -21,9 +22,9 @@ const AssetButton = ({ const { t } = useTranslation('wallet'); const colors = useColors(); const dispatch = useAppDispatch(); - const method = useAppSelector((state) => state.ui.paymentMethod); + const { paymentMethod } = useAppSelector(sendTransactionSelector); - const usesLightning = method === 'lightning'; + const usesLightning = paymentMethod === 'lightning'; const canSwitch = savings && spending; const text = usesLightning ? t('spending.title') : t('savings.title'); @@ -38,8 +39,8 @@ const AssetButton = ({ }; const onSwitch = (): void => { - const paymentMethod = usesLightning ? 'onchain' : 'lightning'; - dispatch(updateUi({ paymentMethod })); + const method = paymentMethod === 'lightning' ? 'onchain' : 'lightning'; + dispatch(updateSendTransaction({ paymentMethod: method })); }; if (!canSwitch) { diff --git a/src/screens/Wallets/Send/Address.tsx b/src/screens/Wallets/Send/Address.tsx index fcb137692..249d71a13 100644 --- a/src/screens/Wallets/Send/Address.tsx +++ b/src/screens/Wallets/Send/Address.tsx @@ -20,12 +20,14 @@ type TValidation = { [x: string]: boolean; }; -const Address = ({}: SendScreenProps<'Address'>): ReactElement => { +const Address = ({ route }: SendScreenProps<'Address'>): ReactElement => { + const uri = route.params?.uri ?? ''; const colors = useColors(); const { t } = useTranslation('wallet'); const { keyboardShown } = useKeyboard(); - const [textFieldValue, setTextFieldValue] = useState(''); - const [isValid, setIsValid] = useState({}); + const [textFieldValue, setTextFieldValue] = useState(uri); + // if a URI is passed in, we assume it's valid + const [isValid, setIsValid] = useState({ [uri]: !!uri }); const onChangeText = async (text: string): Promise => { const diff = Math.abs(text.length - textFieldValue.length); diff --git a/src/screens/Wallets/Send/Amount.tsx b/src/screens/Wallets/Send/Amount.tsx index 9112cc82d..f2ce96fb3 100644 --- a/src/screens/Wallets/Send/Amount.tsx +++ b/src/screens/Wallets/Send/Amount.tsx @@ -48,13 +48,14 @@ import { useBalance, useSwitchUnit } from '../../../hooks/wallet'; import { setupFeeForOnChainTransaction, setupOnChainTransaction, - updateSendTransaction, + updateBeignetSendTransaction, } from '../../../store/actions/wallet'; import { getNumberPadText } from '../../../utils/numberpad'; import { showToast } from '../../../utils/notifications'; import { convertToSats } from '../../../utils/conversion'; import { TRANSACTION_DEFAULTS } from '../../../utils/wallet/constants'; import type { SendScreenProps } from '../../../navigation/types'; +import { sendTransactionSelector } from '../../../store/reselect/ui'; const Amount = ({ navigation }: SendScreenProps<'Amount'>): ReactElement => { const route = useRoute(); @@ -74,8 +75,8 @@ const Amount = ({ navigation }: SendScreenProps<'Amount'>): ReactElement => { const utxos = useAppSelector(utxosSelector); const { onchainBalance } = useBalance(); - const method = useAppSelector((state) => state.ui.paymentMethod); - const usesLightning = method === 'lightning'; + const { paymentMethod } = useAppSelector(sendTransactionSelector); + const usesLightning = paymentMethod === 'lightning'; const outputAmount = useMemo(() => { const amount = getTransactionOutputValue({ outputs: transaction.outputs }); @@ -83,14 +84,14 @@ const Amount = ({ navigation }: SendScreenProps<'Amount'>): ReactElement => { }, [transaction.outputs]); const availableAmount = useMemo(() => { - const maxAmountResponse = getMaxSendAmount({ method }); + const maxAmountResponse = getMaxSendAmount({ method: paymentMethod }); if (maxAmountResponse.isOk()) { return maxAmountResponse.value.amount; } return 0; // recalculate max when utxos, fee or payment method change // eslint-disable-next-line react-hooks/exhaustive-deps - }, [transaction.outputs, transaction.satsPerByte, method]); + }, [transaction.outputs, transaction.satsPerByte, paymentMethod]); useFocusEffect( useCallback(() => { @@ -145,11 +146,11 @@ const Amount = ({ navigation }: SendScreenProps<'Amount'>): ReactElement => { return; } if (isMaxSendAmount && amount !== availableAmount) { - updateSendTransaction({ max: false }); + updateBeignetSendTransaction({ max: false }); } if (!isMaxSendAmount && amount === availableAmount) { - updateSendTransaction({ max: true }); + updateBeignetSendTransaction({ max: true }); } }, [isMaxSendAmount, amount, availableAmount, transaction?.lightningInvoice]); diff --git a/src/screens/Wallets/Send/Error.tsx b/src/screens/Wallets/Send/Error.tsx index a92e4c4b1..8b9120664 100644 --- a/src/screens/Wallets/Send/Error.tsx +++ b/src/screens/Wallets/Send/Error.tsx @@ -15,7 +15,7 @@ import { resetSendTransaction, setupOnChainTransaction, } from '../../../store/actions/wallet'; -import { closeSheet, updateUi } from '../../../store/slices/ui'; +import { closeSheet, updateSendTransaction } from '../../../store/slices/ui'; import { transactionSelector } from '../../../store/reselect/wallet'; const imageCross = require('../../../assets/illustrations/cross.png'); @@ -50,7 +50,7 @@ const Error = ({ const handleRetry = async (): Promise => { if (isSlashpayLightning) { - dispatch(updateUi({ paymentMethod: 'onchain' })); + dispatch(updateSendTransaction({ paymentMethod: 'onchain' })); const res = await processUri({ uri: slashTagsUrl, source: 'send', diff --git a/src/screens/Wallets/Send/ReviewAndSend.tsx b/src/screens/Wallets/Send/ReviewAndSend.tsx index a9325794c..44d0ca957 100644 --- a/src/screens/Wallets/Send/ReviewAndSend.tsx +++ b/src/screens/Wallets/Send/ReviewAndSend.tsx @@ -74,11 +74,12 @@ import { onChainFeesSelector } from '../../../store/reselect/fees'; import { addPendingPayment } from '../../../store/slices/lightning'; import { updateOnChainActivityList } from '../../../store/utils/activity'; import { updateLastPaidContacts } from '../../../store/slices/slashtags'; +import { EActivityType } from '../../../store/types/activity'; +import { sendTransactionSelector } from '../../../store/reselect/ui'; import { ellipsis, truncate } from '../../../utils/helpers'; import AmountToggle from '../../../components/AmountToggle'; import LightningSyncing from '../../../components/LightningSyncing'; import { i18nTime } from '../../../utils/i18n'; -import { EActivityType } from '../../../store/types/activity'; const Section = memo( ({ @@ -124,8 +125,8 @@ const ReviewAndSend = ({ const pin = useAppSelector(pinSelector); const pinForPayments = useAppSelector(pinForPaymentsSelector); const biometrics = useAppSelector((state) => state.settings.biometrics); - const method = useAppSelector((state) => state.ui.paymentMethod); - const usesLightning = method === 'lightning'; + const { paymentMethod, uri } = useAppSelector(sendTransactionSelector); + const usesLightning = paymentMethod === 'lightning'; const [isLoading, setIsLoading] = useState(false); const [showBiotmetrics, setShowBiometrics] = useState(false); @@ -138,23 +139,22 @@ const ReviewAndSend = ({ const [rawTx, setRawTx] = useState<{ hex: string; id: string }>(); const [decodedInvoice, setDecodedInvoice] = useState(); - const decodeAndSetLightningInvoice = async (): Promise => { - try { + useEffect(() => { + const decodeAndSetLightningInvoice = async (): Promise => { if (!usesLightning || !transaction.lightningInvoice) { + setDecodedInvoice(undefined); return; } const result = await decodeLightningInvoice(transaction.lightningInvoice); if (result.isErr()) { + setDecodedInvoice(undefined); + console.log(result.error.message); return; } setDecodedInvoice(result.value); - } catch (e) { - console.log(e); - } - }; + }; - useEffect(() => { - decodeAndSetLightningInvoice().then(); + decodeAndSetLightningInvoice(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [transaction.lightningInvoice]); @@ -168,10 +168,7 @@ const ReviewAndSend = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [transaction.outputs, selectedNetwork, selectedWallet]); - // TODO: add support for multiple outputs - const outputIndex = 0; const { selectedFeeId, satsPerByte } = transaction; - const address = transaction.outputs[outputIndex]?.address ?? ''; const onError = useCallback( (errorMessage: string) => { @@ -484,6 +481,10 @@ const ReviewAndSend = ({ onChainBalance, ]); + const goToAddress = (): void => { + navigation.navigate('Address', { uri }); + }; + const goBackToAmount = useCallback(() => { const { routes } = navigation.getState(); const amountIndex = routes.findLastIndex( @@ -568,12 +569,14 @@ const ReviewAndSend = ({ <> - + @@ -587,13 +590,9 @@ const ReviewAndSend = ({ transaction.slashTagsUrl ? ( ) : ( - <> - {decodedInvoice ? ( - {truncate(decodedInvoice.to_str, 100)} - ) : ( - {ellipsis(address, 25)} - )} - + + {ellipsis(uri, 30)} + ) } /> @@ -676,7 +675,9 @@ const ReviewAndSend = ({
{decodedInvoice?.description}} + value={ + {truncate(decodedInvoice.description, 100)} + } /> ) : null} @@ -722,83 +723,84 @@ const ReviewAndSend = ({ onConfirm={onSwipeToPay} /> - - confirmPayment(dialogWarnings)} - onConfirm={(): void => setShowDialog1(false)} - onCancel={(): void => { - setShowDialog1(false); - setIsLoading(false); - setTimeout(() => navigation.goBack(), 300); - }} - /> - confirmPayment(dialogWarnings)} - onConfirm={(): void => setShowDialog2(false)} - onCancel={(): void => { - setShowDialog2(false); - setIsLoading(false); - setTimeout(() => navigation.goBack(), 300); - }} - /> - confirmPayment(dialogWarnings)} - onConfirm={(): void => setShowDialog3(false)} - onCancel={(): void => { - setShowDialog3(false); - setIsLoading(false); - setTimeout(() => navigation.goBack(), 300); - }} - /> - confirmPayment(dialogWarnings)} - onConfirm={(): void => setShowDialog4(false)} - onCancel={(): void => { - setShowDialog4(false); - setIsLoading(false); - setTimeout(() => navigation.goBack(), 300); - }} - /> - confirmPayment(dialogWarnings)} - onConfirm={(): void => setShowDialog5(false)} - onCancel={(): void => { - setShowDialog5(false); - setIsLoading(false); - setTimeout(() => navigation.goBack(), 300); - }} - /> - + + + confirmPayment(dialogWarnings)} + onConfirm={(): void => setShowDialog1(false)} + onCancel={(): void => { + setShowDialog1(false); + setIsLoading(false); + setTimeout(() => navigation.goBack(), 300); + }} + /> + confirmPayment(dialogWarnings)} + onConfirm={(): void => setShowDialog2(false)} + onCancel={(): void => { + setShowDialog2(false); + setIsLoading(false); + setTimeout(() => navigation.goBack(), 300); + }} + /> + confirmPayment(dialogWarnings)} + onConfirm={(): void => setShowDialog3(false)} + onCancel={(): void => { + setShowDialog3(false); + setIsLoading(false); + setTimeout(() => navigation.goBack(), 300); + }} + /> + confirmPayment(dialogWarnings)} + onConfirm={(): void => setShowDialog4(false)} + onCancel={(): void => { + setShowDialog4(false); + setIsLoading(false); + setTimeout(() => navigation.goBack(), 300); + }} + /> + confirmPayment(dialogWarnings)} + onConfirm={(): void => setShowDialog5(false)} + onCancel={(): void => { + setShowDialog5(false); + setIsLoading(false); + setTimeout(() => navigation.goBack(), 300); + }} + /> + {showBiotmetrics && ( { @@ -826,7 +828,8 @@ const styles = StyleSheet.create({ flex: 1, }, content: { - flex: 1, + // flex: 1, + flexGrow: 1, paddingHorizontal: 16, }, amountToggle: { diff --git a/src/store/actions/wallet.ts b/src/store/actions/wallet.ts index fd75aaf9a..adb974d36 100644 --- a/src/store/actions/wallet.ts +++ b/src/store/actions/wallet.ts @@ -308,7 +308,7 @@ export const getChangeAddress = async ({ * @param {Partial} transaction * @returns {Promise>} */ -export const updateSendTransaction = ( +export const updateBeignetSendTransaction = ( transaction: Partial, ): Result => { const tx = getOnChainWalletTransaction(); diff --git a/src/store/reselect/ui.ts b/src/store/reselect/ui.ts index d52ed0c2a..206a9987a 100644 --- a/src/store/reselect/ui.ts +++ b/src/store/reselect/ui.ts @@ -5,6 +5,7 @@ import { TViewController, TUiViewController, IViewControllerData, + TSendTransaction, } from '../types/ui'; const uiState = (state: RootState): TUiState => state.ui; @@ -92,6 +93,8 @@ export const isElectrumThrottledSelector = createSelector( (ui): boolean => ui.isElectrumThrottled, ); +export const appStateSelector = createSelector([uiState], (ui) => ui.appState); + export const availableUpdateSelector = createSelector( [uiState], (ui) => ui.availableUpdate, @@ -106,9 +109,6 @@ export const timeZoneSelector = createSelector([uiState], (ui) => ui.timeZone); export const languageSelector = createSelector([uiState], (ui) => ui.language); -export const fromAddressViewerSelector = createSelector( - [uiState], - (ui) => ui.fromAddressViewer, -); - -export const appStateSelector = createSelector([uiState], (ui) => ui.appState); +export const sendTransactionSelector = (state: RootState): TSendTransaction => { + return state.ui.sendTransaction; +}; diff --git a/src/store/shapes/ui.ts b/src/store/shapes/ui.ts index 8f1a94f9a..331f01151 100644 --- a/src/store/shapes/ui.ts +++ b/src/store/shapes/ui.ts @@ -30,6 +30,7 @@ export const defaultViewControllers: TUiState['viewControllers'] = { }; export const initialUiState: TUiState = { + appState: 'active', availableUpdate: null, isAuthenticated: false, isConnectedToElectrum: true, @@ -41,7 +42,9 @@ export const initialUiState: TUiState = { timeZone: 'UTC', // Used to control bottom-sheets throughout the app viewControllers: defaultViewControllers, - fromAddressViewer: false, // When true, ensures tx inputs are not cleared when sweeping from address viewer. - paymentMethod: 'onchain', - appState: 'active', + sendTransaction: { + fromAddressViewer: false, // When true, ensures tx inputs are not cleared when sweeping from address viewer. + paymentMethod: 'onchain', + uri: '', + }, }; diff --git a/src/store/slices/ui.ts b/src/store/slices/ui.ts index 03d955d81..b8c79334d 100644 --- a/src/store/slices/ui.ts +++ b/src/store/slices/ui.ts @@ -7,6 +7,7 @@ import { TAvailableUpdate, TProfileLink, ViewControllerParamList, + TSendTransaction, } from '../types/ui'; export const uiSlice = createSlice({ @@ -57,6 +58,15 @@ export const uiSlice = createSlice({ updateProfileLink: (state, action: PayloadAction) => { state.profileLink = Object.assign(state.profileLink, action.payload); }, + updateSendTransaction: ( + state, + action: PayloadAction>, + ) => { + state.sendTransaction = Object.assign( + state.sendTransaction, + action.payload, + ); + }, resetUiState: () => initialUiState, }, }); @@ -70,6 +80,7 @@ export const { toggleSheet, closeSheet, updateProfileLink, + updateSendTransaction, resetUiState, } = actions; diff --git a/src/store/types/ui.ts b/src/store/types/ui.ts index 21deadd57..d7ff4483b 100644 --- a/src/store/types/ui.ts +++ b/src/store/types/ui.ts @@ -81,18 +81,23 @@ export type TAvailableUpdate = { critical: boolean; }; +export type TSendTransaction = { + paymentMethod: 'onchain' | 'lightning'; + uri: string; + fromAddressViewer?: boolean; +}; + export type TUiState = { + appState: AppStateStatus; availableUpdate: TAvailableUpdate | null; isAuthenticated: boolean; isConnectedToElectrum: boolean; isElectrumThrottled: boolean; isOnline: boolean; isLDKReady: boolean; + language: string; profileLink: TProfileLink; - viewControllers: TUiViewController; timeZone: string; - language: string; - fromAddressViewer: boolean; - paymentMethod: 'onchain' | 'lightning'; - appState: AppStateStatus; + viewControllers: TUiViewController; + sendTransaction: TSendTransaction; }; diff --git a/src/store/utils/blocktank.ts b/src/store/utils/blocktank.ts index 6b062fe26..38a1dd877 100644 --- a/src/store/utils/blocktank.ts +++ b/src/store/utils/blocktank.ts @@ -12,7 +12,7 @@ import notifee, { TimestampTrigger, TriggerType } from '@notifee/react-native'; import { __E2E__ } from '../../constants/env'; import { addTransfer, removeTransfer } from '../slices/wallet'; -import { updateSendTransaction } from '../actions/wallet'; +import { updateBeignetSendTransaction } from '../actions/wallet'; import { setLightningSetupStep } from '../slices/user'; import { getBlocktankStore, dispatch, getFeesStore } from '../helpers'; import * as blocktank from '../../utils/blocktank'; @@ -281,7 +281,7 @@ export const startChannelPurchase = async ({ ); } - updateSendTransaction({ + updateBeignetSendTransaction({ outputs: [ { address: buyChannelData.payment.onchain.address, diff --git a/src/utils/scanner/scanner.ts b/src/utils/scanner/scanner.ts index 386152d13..87b9ca9ad 100644 --- a/src/utils/scanner/scanner.ts +++ b/src/utils/scanner/scanner.ts @@ -27,10 +27,10 @@ import { showToast } from '../notifications'; import { resetSendTransaction, setupOnChainTransaction, - updateSendTransaction, + updateBeignetSendTransaction, } from '../../store/actions/wallet'; import { getBalance, getSelectedNetwork, getSelectedWallet } from '../wallet'; -import { closeSheet, updateUi } from '../../store/slices/ui'; +import { closeSheet, updateSendTransaction } from '../../store/slices/ui'; import { showBottomSheet } from '../../store/utils/ui'; import { decodeLightningInvoice, @@ -627,7 +627,7 @@ const handleData = async ({ // Determine initial payment method for 0 amount unified invoice const paymentMethod = preferredPaymentMethod ?? 'lightning'; - dispatch(updateUi({ paymentMethod })); + dispatch(updateSendTransaction({ paymentMethod, uri })); const screen = amount ? 'ReviewAndSend' : 'Amount'; // If BottomSheet is not open yet (MainScanner) @@ -635,7 +635,7 @@ const handleData = async ({ // If BottomSheet is already open (SendScanner) sendNavigation.navigate(screen); - updateSendTransaction({ + updateBeignetSendTransaction({ label: message, outputs: [{ address, value: amount, index: 0 }], lightningInvoice, @@ -651,9 +651,9 @@ const handleData = async ({ await resetSendTransaction(); await setupOnChainTransaction(); - dispatch(updateUi({ paymentMethod: 'onchain' })); + dispatch(updateSendTransaction({ paymentMethod: 'onchain', uri })); - updateSendTransaction({ + updateBeignetSendTransaction({ label: message, outputs: [{ address, value: amount, index: 0 }], slashTagsUrl, @@ -685,7 +685,7 @@ const handleData = async ({ return ok(''); } - dispatch(updateUi({ paymentMethod: 'lightning' })); + dispatch(updateSendTransaction({ paymentMethod: 'lightning', uri })); const invoiceAmount = amount ?? 0; const screen = invoiceAmount ? 'ReviewAndSend' : 'Amount'; @@ -694,7 +694,7 @@ const handleData = async ({ // If BottomSheet is already open (SendScanner) sendNavigation.navigate(screen); - updateSendTransaction({ + updateBeignetSendTransaction({ outputs: [{ address: '', value: invoiceAmount, index: 0 }], lightningInvoice, slashTagsUrl, diff --git a/src/utils/wallet/transactions.ts b/src/utils/wallet/transactions.ts index c9c39663e..f0c1cf3ab 100644 --- a/src/utils/wallet/transactions.ts +++ b/src/utils/wallet/transactions.ts @@ -15,7 +15,7 @@ import { getAddressInfo } from 'bitcoin-address-validation'; import { __E2E__ } from '../../constants/env'; import { addBoostedTransaction, - updateSendTransaction, + updateBeignetSendTransaction, } from '../../store/actions/wallet'; import { dispatch, @@ -470,7 +470,7 @@ export const sendMax = async ({ address?: string; index?: number; } = {}): Promise> => { - const { paymentMethod } = getUiStore(); + const { paymentMethod } = getUiStore().sendTransaction; try { const tx = await getOnChainWalletTransactionAsync(); @@ -573,7 +573,7 @@ export const updateSendAmount = ({ amount: number; transaction?: ISendTransaction; }): Result => { - const { paymentMethod } = getUiStore(); + const { paymentMethod } = getUiStore().sendTransaction; if (!transaction) { transaction = getOnchainTransactionData(); @@ -624,7 +624,7 @@ export const updateSendAmount = ({ return ok('No change detected. No need to update.'); } - updateSendTransaction({ + updateBeignetSendTransaction({ outputs: [{ ...currentOutput, value: amount }], max, }); @@ -667,12 +667,12 @@ export const updateMessage = async ({ }; if (max) { _transaction.outputs = [{ address, value: inputTotal - newFee, index }]; - //Update the tx value with the new fee to continue sending the max amount. - updateSendTransaction(_transaction); + // Update the tx value with the new fee to continue sending the max amount. + updateBeignetSendTransaction(_transaction); return ok('Successfully updated the message.'); } if (totalNewAmount <= inputTotal) { - updateSendTransaction(_transaction); + updateBeignetSendTransaction(_transaction); } return ok('Successfully updated the message.'); }; @@ -733,7 +733,7 @@ const runCoinSelect = async ({ fee: autoCoinSelectResponse.value.fee, inputs: autoCoinSelectResponse.value.inputs, }; - updateSendTransaction(updatedTx); + updateBeignetSendTransaction(updatedTx); return ok('Successfully updated tx.'); } return ok('No need to update transaction.'); diff --git a/src/utils/wallet/transfer.ts b/src/utils/wallet/transfer.ts index 5955553b6..983ed0900 100644 --- a/src/utils/wallet/transfer.ts +++ b/src/utils/wallet/transfer.ts @@ -25,7 +25,7 @@ import { createTransaction } from './transactions'; import { addTransfer } from '../../store/slices/wallet'; import { getNetworkForBeignet, - updateSendTransaction, + updateBeignetSendTransaction, } from '../../store/actions/wallet'; /** @@ -138,7 +138,7 @@ export const createFundedChannel = async ({ const network = getNetworkForBeignet(selectedNetwork); const address = getAddressFromScriptPubKey(output_script, network); - updateSendTransaction({ + updateBeignetSendTransaction({ outputs: [{ address, value: value_satoshis, index: 0 }], });