diff --git a/docker/regtest/dockerfile-deps/joinmarket/latest/Dockerfile b/docker/regtest/dockerfile-deps/joinmarket/latest/Dockerfile index 871c28759..4c33af052 100644 --- a/docker/regtest/dockerfile-deps/joinmarket/latest/Dockerfile +++ b/docker/regtest/dockerfile-deps/joinmarket/latest/Dockerfile @@ -7,9 +7,9 @@ RUN apt-get update \ tor \ && rm -rf /var/lib/apt/lists/* -ENV REPO https://github.com/JoinMarket-Org/joinmarket-clientserver -ENV REPO_BRANCH master -ENV REPO_REF master +ENV REPO https://github.com/amitx13/joinmarket-clientserver +ENV REPO_BRANCH Updating_Direct-Send_RPC-API_to_accept_UTXOs +ENV REPO_REF Updating_Direct-Send_RPC-API_to_accept_UTXOs WORKDIR /src RUN git clone "$REPO" . --depth=10 --branch "$REPO_BRANCH" && git checkout "$REPO_REF" diff --git a/src/components/Send/SendForm.tsx b/src/components/Send/SendForm.tsx index 7eeaf130b..ed724c19b 100644 --- a/src/components/Send/SendForm.tsx +++ b/src/components/Send/SendForm.tsx @@ -214,6 +214,7 @@ export interface SendFormValues { txFee?: TxFee isCoinJoin: boolean numCollaborators?: number + consideredUtxos?: string[] } interface InnerSendFormProps { diff --git a/src/components/Send/SourceJarSelector.tsx b/src/components/Send/SourceJarSelector.tsx index af6e9ccb5..92c150e06 100644 --- a/src/components/Send/SourceJarSelector.tsx +++ b/src/components/Send/SourceJarSelector.tsx @@ -3,7 +3,7 @@ import { useField, useFormikContext } from 'formik' import * as rb from 'react-bootstrap' import { jarFillLevel, SelectableJar } from '../jars/Jar' import { noop } from '../../utils' -import { WalletInfo, CurrentWallet, useReloadCurrentWalletInfo, Utxo } from '../../context/WalletContext' +import { WalletInfo, CurrentWallet, useReloadCurrentWalletInfo, Utxo, Utxos } from '../../context/WalletContext' import styles from './SourceJarSelector.module.css' import { ShowUtxos } from './ShowUtxos' import { useTranslation } from 'react-i18next' @@ -38,6 +38,7 @@ export const SourceJarSelector = ({ }: SourceJarSelectorProps) => { const { t } = useTranslation() const [field] = useField(name) + const [consideredUtxos] = useField('consideredUtxos') const form = useFormikContext() const reloadCurrentWalletInfo = useReloadCurrentWalletInfo() @@ -109,9 +110,21 @@ export const SourceJarSelector = ({ if (res.length !== 0) { setIsUtxosLoading(true) - await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal }) + const allUtxosData = await reloadCurrentWalletInfo.reloadUtxos({ signal: abortCtrl.signal }) + if (allUtxosData) { + const selectedUtxos = allUtxosData.utxos + .filter((utxo) => utxo.mixdepth === field.value && !utxo.frozen) + .map((utxo) => utxo.utxo) + form.setFieldValue(consideredUtxos.name, selectedUtxos, true) + } + } else { + if (walletInfo) { + const selectedUtxos = walletInfo.utxosByJar[field.value] + .filter((utxo) => !utxo.frozen) + .map((utxo) => utxo.utxo) + form.setFieldValue(consideredUtxos.name, selectedUtxos, true) + } } - setShowUtxos(undefined) } catch (err: any) { if (!abortCtrl.signal.aborted) { @@ -120,7 +133,7 @@ export const SourceJarSelector = ({ } finally { setIsUtxosLoading(false) } - }, [frozenUtxos, unFrozenUtxos, wallet, reloadCurrentWalletInfo]) + }, [frozenUtxos, unFrozenUtxos, wallet, reloadCurrentWalletInfo, consideredUtxos, form, field, walletInfo]) return ( <> @@ -165,6 +178,7 @@ export const SourceJarSelector = ({ variant={it.accountIndex === field.value ? variant : undefined} onClick={(jarIndex: number) => { form.setFieldValue(field.name, jarIndex, true) + form.setFieldValue(consideredUtxos.name, undefined, false) if ( it.accountIndex === field.value && !disabled && diff --git a/src/components/Send/index.tsx b/src/components/Send/index.tsx index 7f6dd561d..58a1adeff 100644 --- a/src/components/Send/index.tsx +++ b/src/components/Send/index.tsx @@ -12,7 +12,7 @@ import { scrollToTop } from '../../utils' import { PaymentConfirmModal } from '../PaymentConfirmModal' import FeeConfigModal, { FeeConfigSectionKey } from '../settings/FeeConfigModal' import { FeeValues, TxFee, useFeeConfigValues } from '../../hooks/Fees' -import { useReloadCurrentWalletInfo, useCurrentWalletInfo, CurrentWallet } from '../../context/WalletContext' +import { useReloadCurrentWalletInfo, useCurrentWalletInfo, CurrentWallet, Utxos } from '../../context/WalletContext' import { useServiceInfo, useReloadServiceInfo } from '../../context/ServiceInfoContext' import { useLoadConfigValue } from '../../context/ServiceConfigContext' import { useWaitForUtxosToBeSpent } from '../../hooks/WaitForUtxosToBeSpent' @@ -20,6 +20,8 @@ import { routes } from '../../constants/routes' import { JM_MINIMUM_MAKERS_DEFAULT } from '../../constants/config' import { initialNumCollaborators } from './helpers' +import { Divider, UtxoListDisplay } from './ShowUtxos' +import { useSettings } from '../../context/SettingsContext' const INITIAL_DESTINATION = null const INITIAL_SOURCE_JAR_INDEX = null @@ -79,6 +81,29 @@ const createInitialValues = (numCollaborators: number, feeConfigValues: FeeValue } } +type ReviewConsideredUtxosProps = { + utxos: Utxos +} +const ReviewConsideredUtxos = ({ utxos }: ReviewConsideredUtxosProps) => { + const { t } = useTranslation() + const settings = useSettings() + const [isOpen, setIsOpen] = useState(false) + + return ( + + + {t('show_utxos.considered_utxos')} + + + + {isOpen && ( + + )} + + + ) +} + type SendProps = { wallet: CurrentWallet } @@ -238,6 +263,7 @@ export default function Send({ wallet }: SendProps) { destination: Api.BitcoinAddress, amountSats: Api.AmountSats, txFee: TxFee, + consideredUtxos?: string[], ) => { setAlert(undefined) setPaymentSuccessfulInfoAlert(undefined) @@ -247,7 +273,13 @@ export default function Send({ wallet }: SendProps) { try { const res = await Api.postDirectSend( { ...wallet }, - { mixdepth: sourceJarIndex, amount_sats: amountSats, destination, txfee: txFee.value }, + { + mixdepth: sourceJarIndex, + amount_sats: amountSats, + destination, + txfee: txFee.value, + selected_utxos: consideredUtxos, + }, ) if (res.ok) { @@ -395,7 +427,13 @@ export default function Send({ wallet }: SendProps) { values.numCollaborators!, values.txFee!, ) - : await sendPayment(values.sourceJarIndex!, values.destination!.value!, values.amount!.value, values.txFee!) + : await sendPayment( + values.sourceJarIndex!, + values.destination!.value!, + values.amount!.value, + values.txFee!, + values.consideredUtxos, + ) if (success) { formRef.current?.resetForm({ values: initialValues }) @@ -516,7 +554,18 @@ export default function Send({ wallet }: SendProps) { numCollaborators: showConfirmSendModal.numCollaborators!, feeConfigValues: { ...feeConfigValues, tx_fees: showConfirmSendModal.txFee }, }} - /> + > + {showConfirmSendModal.consideredUtxos && + walletInfo && + showConfirmSendModal.sourceJarIndex !== undefined && + (() => { + const selectedUtxosList = showConfirmSendModal.consideredUtxos + const utxoList = walletInfo.utxosByJar[showConfirmSendModal.sourceJarIndex].filter((utxo) => + selectedUtxosList.some((selectedUtxos) => selectedUtxos === utxo.utxo), + ) + return + })()} + )} ) diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index fcbdf99f4..0693fc6ea 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -703,7 +703,7 @@ }, "show_utxos": { "select_utxos": "Select UTXOs", - "selected_utxos": "Selected UTXOs", + "considered_utxos": "Considered UTXOs", "show_utxo_title": "Select UTXOs to be considered", "show_utxo_subtitle": "The following UTXOs are considered in the transaction. Every unselected UTXO will be frozen and can be unfrozen later on.", "show_utxo_subtitle_when_allutxos_are_frozen": "The following UTXOs are frozen. Please select them to be considered in the transaction.", diff --git a/src/libs/JmWalletApi.ts b/src/libs/JmWalletApi.ts index 7db9c2184..0f5294745 100644 --- a/src/libs/JmWalletApi.ts +++ b/src/libs/JmWalletApi.ts @@ -113,6 +113,7 @@ interface DirectSendRequest { destination: BitcoinAddress amount_sats: AmountSats txfee?: number + selected_utxos?: string[] } interface DoCoinjoinRequest {