Skip to content

Commit

Permalink
wip: use new scheduler preconditions in Jam component
Browse files Browse the repository at this point in the history
  • Loading branch information
theborakompanioni committed Sep 12, 2022
1 parent 5745813 commit ec5c3e5
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 46 deletions.
135 changes: 95 additions & 40 deletions src/components/Jam.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react'
import React, { useState, useEffect, useCallback, useMemo, forwardRef } from 'react'
import * as rb from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next'
import { Formik, useFormikContext } from 'formik'
Expand All @@ -7,18 +7,16 @@ import { useSettings } from '../context/SettingsContext'
import { useServiceInfo, useReloadServiceInfo } from '../context/ServiceInfoContext'
import { useCurrentWallet, useCurrentWalletInfo, useReloadCurrentWalletInfo } from '../context/WalletContext'
import { isDebugFeatureEnabled } from '../constants/debugFeatures'
import {
COINJOIN_PRECONDITIONS,
buildCoinjoinPreconditionSummary,
useCoinjoinPreconditionSummary,
} from '../hooks/CoinjoinPrecondition'
import { DEFAULT_REQUIREMENT_OPTIONS, buildCoinjoinRequirementSummary } from '../hooks/CoinjoinRequirements'
import PageTitle from './PageTitle'
import ToggleSwitch from './ToggleSwitch'
import Sprite from './Sprite'
import Balance from './Balance'
import ScheduleProgress from './ScheduleProgress'

import styles from './Jam.module.css'
import { jarInitial } from './jars/Jar'
import { shortenStringMiddle } from '../utils'

// When running the scheduler with internal destination addresses, the funds
// will end up on those 3 mixdepths (one UTXO each).
Expand All @@ -27,6 +25,8 @@ const INTERNAL_DEST_ACCOUNTS = [0, 1, 2]
// Interval in milliseconds between requests to reload the schedule.
const SCHEDULER_STOP_RESPONSE_DELAY_MS = 2_000

const COINJOIN_REQUIREMENT_OPTIONS = DEFAULT_REQUIREMENT_OPTIONS

const ValuesListener = ({ handler }) => {
const { values } = useFormikContext()

Expand All @@ -39,6 +39,90 @@ const ValuesListener = ({ handler }) => {
return null
}

const CoinjoinRequirementViolationAlert = forwardRef(({ schedulerPreconditionSummary }, ref) => {
const { t } = useTranslation()
const settings = useSettings()

if (schedulerPreconditionSummary.isFulfilled) return <></>

if (schedulerPreconditionSummary.numberOfMissingUtxos > 0) {
return (
<rb.Alert variant="warning" className="mb-4" ref={ref}>
{t('scheduler.precondition.hint_missing_utxos', {
minConfirmations: COINJOIN_REQUIREMENT_OPTIONS.minConfirmations,
})}
</rb.Alert>
)
}

if (schedulerPreconditionSummary.numberOfMissingConfirmations > 0) {
return (
<rb.Alert variant="warning" className="mb-4" ref={ref}>
{t('scheduler.precondition.hint_missing_confirmations', {
minConfirmations: COINJOIN_REQUIREMENT_OPTIONS.minConfirmations,
amountOfMissingConfirmations: schedulerPreconditionSummary.numberOfMissingConfirmations,
})}
</rb.Alert>
)
}

const utxosViolatingRetriesLeft = schedulerPreconditionSummary.violations
.map((it) => it.utxosViolatingRetriesLeft)
.reduce((acc, utxos) => acc.concat(utxos), [])

if (utxosViolatingRetriesLeft.length > 0) {
return (
<rb.Alert variant="danger" className="mb-4" ref={ref}>
<>
<Trans i18nKey="scheduler.precondition.hint_missing_retries">
You tried too many times. See
<a
href="https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/v0.9.7/docs/SOURCING-COMMITMENTS.md"
target="_blank"
rel="noopener noreferrer"
>
the docs
</a>{' '}
for more info.
</Trans>
<br />
<br />
<Trans i18nKey="scheduler.precondition.hint_missing_retries_detail" count={utxosViolatingRetriesLeft.length}>
Following utxos have been used unsuccessfully too many times:
<ul className="mt-2 ps-2">
{utxosViolatingRetriesLeft.map((utxo, index) => (
<li key={index} className="mb-2 slashed-zeroes small" style={{ display: 'inline-flex' }}>
<span className="pe-1" style={{ display: 'inline-flex' }}>
<Sprite symbol="jar-closed-fill-50" width="20" height="20" />
<span className="slashed-zeroes">
<strong>{jarInitial(utxo.mixdepth)}</strong>
</span>
:
</span>
<div>
<span>{utxo.address}</span>
&nbsp;(
<Balance
valueString={`${utxo.value}`}
convertToUnit={settings.unit}
showBalance={settings.showBalance}
/>
)
<br />
<small>{shortenStringMiddle(utxo.utxo, 32)}</small>
</div>
</li>
))}
</ul>
</Trans>
</>
</rb.Alert>
)
}

return <></>
})

export default function Jam() {
const { t } = useTranslation()
const settings = useSettings()
Expand All @@ -52,7 +136,10 @@ export default function Jam() {
const [isLoading, setIsLoading] = useState(true)
const [collaborativeOperationRunning, setCollaborativeOperationRunning] = useState(false)

const schedulerPreconditionSummary = useCoinjoinPreconditionSummary(walletInfo?.data.utxos.utxos || [])
const schedulerPreconditionSummary = useMemo(
() => buildCoinjoinRequirementSummary(walletInfo?.data.utxos.utxos || []),
[walletInfo]
)
const isSchedulerPreconditionsFulfilled = useMemo(
() => schedulerPreconditionSummary.isFulfilled,
[schedulerPreconditionSummary]
Expand Down Expand Up @@ -217,39 +304,7 @@ export default function Jam() {
mountOnEnter={true}
unmountOnExit={true}
>
<rb.Alert variant="warning" className="mb-4">
<>
{schedulerPreconditionSummary.numberOfMissingUtxos > 0 ? (
<>
{t('scheduler.precondition.hint_missing_utxos', {
minConfirmations: COINJOIN_PRECONDITIONS.MIN_CONFIRMATIONS,
amountOfMissingConfirmations: COINJOIN_PRECONDITIONS.MIN_CONFIRMATIONS,
})}
</>
) : schedulerPreconditionSummary.amountOfMissingConfirmations > 0 ? (
<>
{t('scheduler.precondition.hint_missing_confirmations', {
minConfirmations: COINJOIN_PRECONDITIONS.MIN_CONFIRMATIONS,
amountOfMissingConfirmations: schedulerPreconditionSummary.amountOfMissingConfirmations,
})}
</>
) : (
schedulerPreconditionSummary.amountOfMissingOverallRetries > 0 && (
<Trans i18nKey="scheduler.precondition.hint_missing_overall_retries">
You tried too many times. See
<a
href="https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/v0.9.6/docs/SOURCING-COMMITMENTS.md"
target="_blank"
rel="noopener noreferrer"
>
the docs
</a>{' '}
for more info.
</Trans>
)
)}
</>
</rb.Alert>
<CoinjoinRequirementViolationAlert schedulerPreconditionSummary={schedulerPreconditionSummary} />
</rb.Fade>
{!collaborativeOperationRunning && walletInfo && (
<>
Expand Down
3 changes: 1 addition & 2 deletions src/components/Send.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ function CoinjoinPreconditionFailedAlert({ coinjoinPreconditionSummary }) {
<>
{t('send.coinjoin_precondition.hint_missing_utxos', {
minConfirmations: COINJOIN_PRECONDITIONS.MIN_CONFIRMATIONS,
amountOfMissingConfirmations: COINJOIN_PRECONDITIONS.MIN_CONFIRMATIONS,
})}
</>
) : coinjoinPreconditionSummary.amountOfMissingConfirmations > 0 ? (
Expand All @@ -234,7 +233,7 @@ function CoinjoinPreconditionFailedAlert({ coinjoinPreconditionSummary }) {
</>
) : (
coinjoinPreconditionSummary.amountOfMissingOverallRetries > 0 && (
<Trans i18nKey="scheduler.precondition.hint_missing_overall_retries">
<Trans i18nKey="scheduler.precondition.hint_missing_retries">
You tried too many times. See
<a
href="https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/v0.9.6/docs/SOURCING-COMMITMENTS.md"
Expand Down
10 changes: 6 additions & 4 deletions src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,9 @@
"text_collaborative_tx_disabled": "Payment without privacy improvement"
},
"coinjoin_precondition": {
"hint_missing_utxos": "To execute a collaborative transaction you need UTXOs with {{ minConfirmations }} or more confirmations in the source jar. $t(send.coinjoin_precondition.nested_hint_fund_jar, {\"count\": {{ amountOfMissingConfirmations }} })",
"hint_missing_utxos": "To execute a collaborative transaction you need UTXOs with {{ minConfirmations }} or more confirmations in the source jar. $t(send.coinjoin_precondition.nested_hint_fund_jar, {\"count\": {{ minConfirmations }} })",
"hint_missing_confirmations": "A collaborative transaction requires your UTXOs to have {{ minConfirmations }} or more confirmations. $t(send.coinjoin_precondition.nested_hint_wait_for_block, {\"count\": {{ amountOfMissingConfirmations }} })",
"hint_missing_overall_retries": "You've tried executing a collaborative transaction from this jar unsuccessfully too many times in a row. For security reasons, you need a fresh UTXO to try again. See <1>the docs</1> for more information.",
"hint_missing_retries": "You've tried executing a collaborative transaction from this jar unsuccessfully too many times in a row. For security reasons, you need a fresh UTXO to try again. See <1>the docs</1> for more information.",
"nested_hint_wait_for_block": "Select another jar to send from or wait for one more block.",
"nested_hint_wait_for_block_other": "Select another jar to send from or wait for {{ count }} more blocks.",
"nested_hint_fund_jar": "Select another jar to send from or fund this jar and wait for one block.",
Expand Down Expand Up @@ -457,9 +457,11 @@
"progress_current_state": "Waiting for transaction <1>{{ current }}</1> of <3>{{ total }}</3> to process...",
"progress_done": "All transactions completed successfully. The scheduler will stop soon.",
"precondition": {
"hint_missing_utxos": "To run the scheduler you need UTXOs with {{ minConfirmations }} or more confirmations. $t(scheduler.precondition.nested_hint_fund_wallet, {\"count\": {{ amountOfMissingConfirmations }} })",
"hint_missing_utxos": "To run the scheduler you need UTXOs with {{ minConfirmations }} or more confirmations. $t(scheduler.precondition.nested_hint_fund_wallet, {\"count\": {{ minConfirmations }} })",
"hint_missing_confirmations": "The scheduler requires your UTXOs to have {{ minConfirmations }} or more confirmations. $t(scheduler.precondition.nested_hint_wait_for_block, {\"count\": {{ amountOfMissingConfirmations }} })",
"hint_missing_overall_retries": "You've tried running the scheduler unsuccessfully too many times in a row. For security reasons, you need a fresh UTXO to try again. See <1>the docs</1> for more information.",
"hint_missing_retries": "The scheduler failed to send transactions too many times in a row. See <1>the docs</1> for more information.",
"hint_missing_retries_detail_one": "The following utxo has been used unsuccessfully too many times and cannot be reused: <1></1>",
"hint_missing_retries_detail_other": "The following {{ count }} utxos have been used unsuccessfully too many times and cannot be reused: <1></1>",
"nested_hint_wait_for_block": "Wait for one more block.",
"nested_hint_wait_for_block_other": "Wait for {{ count }} more blocks.",
"nested_hint_fund_wallet": "Fund your wallet and wait for one more block.",
Expand Down
19 changes: 19 additions & 0 deletions src/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { shortenStringMiddle } from './utils'

describe('shortenStringMiddle', () => {
it('should shorten string in the middle', () => {
expect(shortenStringMiddle('0')).toBe('0')
expect(shortenStringMiddle('01')).toBe('01')
expect(shortenStringMiddle('01', -1)).toBe('01')
expect(shortenStringMiddle('01', 0)).toBe('01')
expect(shortenStringMiddle('01', 1)).toBe('01')
expect(shortenStringMiddle('01', 2)).toBe('01')
expect(shortenStringMiddle('0123456789abcdef', 2)).toBe('0…f')
expect(shortenStringMiddle('0123456789abcdef', 8)).toBe('0123…cdef')
expect(shortenStringMiddle('0123456789abcdef', 8, '...')).toBe('0123...cdef')
expect(shortenStringMiddle('0123456789abcdef', 14)).toBe('0123456…9abcdef')
expect(shortenStringMiddle('0123456789abcdef', 15)).toBe('0123456789abcdef')
expect(shortenStringMiddle('0123456789abcdef', 16)).toBe('0123456789abcdef')
expect(shortenStringMiddle('0123456789abcdef', Number.MAX_SAFE_INTEGER)).toBe('0123456789abcdef')
})
})
8 changes: 8 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,11 @@ export const formatBtc = (value: number) => {
export const formatSats = (value: number) => {
return SATS_FORMATTER.format(value)
}

export const shortenStringMiddle = (value: string, chars = 8, separator = '…') => {
const prefixLength = Math.max(Math.floor(chars / 2), 1)
if (value.length <= prefixLength * 2) {
return `${value}`
}
return `${value.substring(0, prefixLength)}${separator}${value.substring(value.length - prefixLength)}`
}

0 comments on commit ec5c3e5

Please sign in to comment.