Skip to content

Commit

Permalink
feat: show address reuse warning (#411)
Browse files Browse the repository at this point in the history
* feat: show address reuse warning

* Update src/i18n/locales/en/translation.json

Co-authored-by: Thebora Kompanioni <theborakompanioni@users.noreply.github.com>

* fix: typo

* fix: add null check

* feat: do not allow sending to reused address

Co-authored-by: Thebora Kompanioni <theborakompanioni@users.noreply.github.com>
  • Loading branch information
Daniel and theborakompanioni committed Jul 21, 2022
1 parent dc36271 commit b2faeb7
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 31 deletions.
87 changes: 57 additions & 30 deletions src/components/Send.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ export default function Send() {
const [isSweep, setIsSweep] = useState(false)
const [destinationJarPickerShown, setDestinationJarPickerShown] = useState(false)
const [destinationJar, setDestinationJar] = useState(null)
const [destinationIsReusedAddress, setDestinationIsReusedAddress] = useState(false)

const [waitForUtxosToBeSpent, setWaitForUtxosToBeSpent] = useState([])
const [paymentSuccessfulInfoAlert, setPaymentSuccessfulInfoAlert] = useState(null)
Expand Down Expand Up @@ -325,6 +326,7 @@ export default function Send() {
useEffect(() => {
if (
isValidAddress(destination) &&
!destinationIsReusedAddress &&
isValidAccount(account) &&
isValidAmount(amount, isSweep) &&
(isCoinjoin ? isValidNumCollaborators(numCollaborators, minNumCollaborators) : true) &&
Expand All @@ -343,6 +345,7 @@ export default function Send() {
isCoinjoin,
isSweep,
coinjoinPreconditionSummary,
destinationIsReusedAddress,
])

useEffect(() => {
Expand Down Expand Up @@ -441,6 +444,17 @@ export default function Send() {
return () => abortCtrl.abort()
}, [isOperationDisabled, wallet, reloadCurrentWalletInfo, reloadServiceInfo, loadConfigValue, t])

useEffect(() => {
if (destination !== null && walletInfo?.addressSummary[destination]) {
if (walletInfo?.addressSummary[destination].status !== 'new') {
setDestinationIsReusedAddress(true)
return
}
}

setDestinationIsReusedAddress(false)
}, [walletInfo, destination])

const sendPayment = async (account, destination, amount_sats) => {
setAlert(null)
setPaymentSuccessfulInfoAlert(null)
Expand Down Expand Up @@ -823,42 +837,55 @@ export default function Send() {
})}
value={destinationJar !== null ? `Jar #${destinationJar} (${destination})` : destination || ''}
required
onChange={(e) => setDestination(e.target.value)}
isInvalid={destination !== null && !isValidAddress(destination)}
disabled={isOperationDisabled || destinationJar !== null}
/>
<rb.Button
variant="outline-dark"
className={styles['button-jar-selector']}
onClick={() => {
if (destinationJar !== null) {
setDestinationJar(null)
setDestination(INITIAL_DESTINATION)
onChange={(e) => {
const value = e.target.value
if (value === '') {
setDestination(null)
} else {
setDestinationJarPickerShown(true)
setDestination(e.target.value)
}
}}
disabled={isOperationDisabled}
>
{destinationJar !== null ? (
<div className="d-flex justify-content-center align-items-center">
<Sprite symbol="cancel" width="26" height="26" />
</div>
) : (
<div className="d-flex justify-content-center align-items-center">
<Sprite
symbol="jar-closed-empty"
width="28px"
height="28px"
style={{ paddingBottom: '0.2rem' }}
/>
</div>
)}
</rb.Button>
isInvalid={(destination !== null && !isValidAddress(destination)) || destinationIsReusedAddress}
disabled={isOperationDisabled || destinationJar !== null}
/>
{destinationIsReusedAddress && (
<rb.Form.Control.Feedback type="invalid">
{t('send.feedback_reused_address')}
</rb.Form.Control.Feedback>
)}
{!destinationIsReusedAddress && (
<rb.Button
variant="outline-dark"
className={styles['button-jar-selector']}
onClick={() => {
if (destinationJar !== null) {
setDestinationJar(null)
setDestination(INITIAL_DESTINATION)
} else {
setDestinationJarPickerShown(true)
}
}}
disabled={isOperationDisabled}
>
{destinationJar !== null ? (
<div className="d-flex justify-content-center align-items-center">
<Sprite symbol="cancel" width="26" height="26" />
</div>
) : (
<div className="d-flex justify-content-center align-items-center">
<Sprite
symbol="jar-closed-empty"
width="28px"
height="28px"
style={{ paddingBottom: '0.2rem' }}
/>
</div>
)}
</rb.Button>
)}
</>
)}
</div>
<rb.Form.Control.Feedback type="invalid">{t('send.feedback_invalid_recipient')}</rb.Form.Control.Feedback>
</rb.Form.Group>
<rb.Form.Group controlId="isCoinjoin" className={`${isCoinjoin ? 'mb-3' : ''}`}>
<ToggleSwitch
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@
"text_coinjoin_already_running": "A collaborative transaction is currently in progress.",
"label_recipient": "Recipient",
"placeholder_recipient": "Enter address or choose jar from wallet...",
"feedback_invalid_recipient": "Please provide a recipient address.",
"feedback_reused_address": "This address is already used. To preserve your privacy please choose another one.",
"label_account": "Send from",
"label_account_dev_mode": "Account to send from",
"account_selector_option": "Jar {{ number }}",
Expand Down

0 comments on commit b2faeb7

Please sign in to comment.