mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-10-05 19:28:26 +00:00
Onchain pay: one card, and honour the payee's BIP21 description
Address and description now share a single card, separated by a rule, instead of
sitting in two cards that read as two unrelated decisions.
The description is READ-ONLY and there is no field for the user to write their
own. A NUT-30 melt request carries {quote, fee_index, inputs, outputs}, and a
Bitcoin transaction has nowhere to put a message either, so nothing the user
typed could ever reach the recipient — and everywhere else in this wallet a memo
IS for the payee, so an editable one here would mean the same word promising
something different on one screen.
What the payee sends is a different thing entirely. BIP21 label/message is their
own text arriving with the request, so the wallet honours it exactly as it
honours a bolt11 invoice's description: shown on the pay screen, saved to
transaction.memo, visible in history. The row is absent when the URI carried
none.
87 tsc (unchanged baseline), 320/320, i18n clean.
This commit is contained in:
@@ -309,6 +309,7 @@
|
||||
"onchainTransferScreen_feeTierBlocks": "About %{blocks} blocks",
|
||||
"onchainTransferScreen_feeTierReserve": "Up to %{amount} %{currency}",
|
||||
"onchainTransferScreen_feeTierSubtext": "About %{blocks} blocks · up to %{amount} %{currency}",
|
||||
"onchainTransferScreen_memoFromPayee": "Payment description",
|
||||
"onchainTransferScreen_networkFee": "Network fee",
|
||||
"onchainTransferScreen_noFeeOptions": "The mint returned no fee options for this payment and it can not be paid.",
|
||||
"onchainTransferScreen_requestQuote": "Continue",
|
||||
|
||||
@@ -308,6 +308,7 @@
|
||||
"onchainTransferScreen_feeTierBlocks": "Unos %{blocks} bloques",
|
||||
"onchainTransferScreen_feeTierReserve": "Hasta %{amount} %{currency}",
|
||||
"onchainTransferScreen_feeTierSubtext": "Unos %{blocks} bloques · hasta %{amount} %{currency}",
|
||||
"onchainTransferScreen_memoFromPayee": "Descripción del pago",
|
||||
"onchainTransferScreen_networkFee": "Tarifa de red",
|
||||
"onchainTransferScreen_noFeeOptions": "La casa de cambio no devolvió opciones de tarifa para este pago y no se puede pagar.",
|
||||
"onchainTransferScreen_requestQuote": "Continuar",
|
||||
|
||||
@@ -309,6 +309,7 @@
|
||||
"onchainTransferScreen_feeTierBlocks": "Cerca de %{blocks} blocos",
|
||||
"onchainTransferScreen_feeTierReserve": "Até %{amount} %{currency}",
|
||||
"onchainTransferScreen_feeTierSubtext": "Cerca de %{blocks} blocos · até %{amount} %{currency}",
|
||||
"onchainTransferScreen_memoFromPayee": "Descrição do pagamento",
|
||||
"onchainTransferScreen_networkFee": "Taxa de rede",
|
||||
"onchainTransferScreen_noFeeOptions": "A casa da moeda não devolveu opções de taxa para este pagamento e não pode ser pago.",
|
||||
"onchainTransferScreen_requestQuote": "Continuar",
|
||||
|
||||
@@ -309,6 +309,7 @@
|
||||
"onchainTransferScreen_feeTierBlocks": "Približne %{blocks} blokov",
|
||||
"onchainTransferScreen_feeTierReserve": "Až do %{amount} %{currency}",
|
||||
"onchainTransferScreen_feeTierSubtext": "Približne %{blocks} blokov · až do %{amount} %{currency}",
|
||||
"onchainTransferScreen_memoFromPayee": "Popis platby",
|
||||
"onchainTransferScreen_networkFee": "Sieťový poplatok",
|
||||
"onchainTransferScreen_noFeeOptions": "Mincovňa nevrátila žiadne možnosti poplatku pre túto platbu, nedá sa zaplatiť.",
|
||||
"onchainTransferScreen_requestQuote": "Pokračovať",
|
||||
|
||||
@@ -19,7 +19,7 @@ import {StackActions, StaticScreenProps, useNavigation} from '@react-navigation/
|
||||
import {TextInput, TextStyle, View, ViewStyle} from 'react-native'
|
||||
import numbro from 'numbro'
|
||||
import {MeltQuoteOnchainResponse} from '@cashu/cashu-ts'
|
||||
import {colors, spacing, typography, useThemeColor} from '../theme'
|
||||
import {colors, spacing, useThemeColor} from '../theme'
|
||||
import {
|
||||
AmountInput,
|
||||
BottomModal,
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
Screen,
|
||||
Text,
|
||||
} from '../components'
|
||||
import {MemoInputCard} from '../components/MemoInputCard'
|
||||
import {useStores} from '../models'
|
||||
import {MintBalance} from '../models/Mint'
|
||||
import {Transaction, TransactionStatus} from '../models/Transaction'
|
||||
@@ -60,6 +59,7 @@ type Props = StaticScreenProps<{
|
||||
address: string
|
||||
/** BIP21 amount hint, in sats. The user may change it. */
|
||||
amountSat?: number
|
||||
/** BIP21 label/message: the PAYEE's description. Read-only. */
|
||||
memo?: string
|
||||
unit: MintUnit
|
||||
mintUrl?: string
|
||||
@@ -255,8 +255,8 @@ export const OnchainTransferScreen = observer(function OnchainTransferScreen({ro
|
||||
|
||||
unitRef.current = unit
|
||||
|
||||
// BIP21 hints. Both are the payee's suggestion, not a commitment: the user can
|
||||
// change the amount, and the mint prices the payment from what they confirm.
|
||||
// The BIP21 amount is the payee's suggestion, not a commitment: the user can
|
||||
// change it, and the mint prices the payment from what they confirm.
|
||||
if (amountSat && amountSat > 0) {
|
||||
setAmountToTransfer(
|
||||
numbro(amountSat).format({thousandSeparated: true, mantissa: 0}),
|
||||
@@ -527,36 +527,60 @@ export const OnchainTransferScreen = observer(function OnchainTransferScreen({ro
|
||||
</View>
|
||||
|
||||
<View style={$contentContainer}>
|
||||
{/*
|
||||
* Destination, and the payee's description of the payment when the BIP21 URI
|
||||
* carried one.
|
||||
*
|
||||
* The memo is READ-ONLY, and there is no field for the user to write their
|
||||
* own. A NUT-30 melt request carries {quote, fee_index, inputs, outputs}, and
|
||||
* a Bitcoin transaction has nowhere to put a message either — so nothing they
|
||||
* typed could reach anyone. What the payee sent, though, is real: it is their
|
||||
* text, arriving with the request, and the wallet honours it exactly as it
|
||||
* honours a bolt11 invoice's description — displayed here, saved on the
|
||||
* transaction, visible in history.
|
||||
*/}
|
||||
{!isSettled && (
|
||||
<Card
|
||||
style={$card}
|
||||
ContentComponent={
|
||||
<ListItem
|
||||
tx="onchainTransferScreen_toAddress"
|
||||
subText={address}
|
||||
subTextEllipsizeMode="middle"
|
||||
LeftComponent={
|
||||
<Icon
|
||||
containerStyle={$iconContainer}
|
||||
icon="faBitcoin"
|
||||
size={spacing.medium}
|
||||
color={iconColor}
|
||||
<>
|
||||
<ListItem
|
||||
tx="onchainTransferScreen_toAddress"
|
||||
subText={address}
|
||||
subTextEllipsizeMode="middle"
|
||||
LeftComponent={
|
||||
<Icon
|
||||
containerStyle={$iconContainer}
|
||||
icon="faBitcoin"
|
||||
size={spacing.medium}
|
||||
color={iconColor}
|
||||
/>
|
||||
}
|
||||
bottomSeparator={!!memo}
|
||||
style={$item}
|
||||
/>
|
||||
{!!memo && (
|
||||
<ListItem
|
||||
tx="onchainTransferScreen_memoFromPayee"
|
||||
subText={memo}
|
||||
LeftComponent={
|
||||
<Icon
|
||||
containerStyle={$iconContainer}
|
||||
icon="faInfoCircle"
|
||||
size={spacing.medium}
|
||||
color={iconColor}
|
||||
/>
|
||||
}
|
||||
style={$item}
|
||||
/>
|
||||
}
|
||||
style={$item}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!hasQuote && !isSettled && (
|
||||
<>
|
||||
<MemoInputCard
|
||||
memo={memo}
|
||||
setMemo={setMemo}
|
||||
onMemoDone={() => {}}
|
||||
disabled={false}
|
||||
/>
|
||||
<Text
|
||||
size="xxs"
|
||||
tx="onchainTransferScreen_feeHint"
|
||||
|
||||
@@ -33,7 +33,14 @@ export type BtcAddressData = {
|
||||
address: string
|
||||
/** BIP21 `amount`, in sats. A hint from the payee — the user may change it. */
|
||||
amountSat?: number
|
||||
/** BIP21 `label`/`message`, offered as the transaction memo. */
|
||||
/**
|
||||
* BIP21 `label`/`message`: the PAYEE's description of what this payment is for.
|
||||
*
|
||||
* Not something the user writes — an onchain melt has no field that could carry a
|
||||
* message out. This is the payee's own text arriving with the request, so the wallet
|
||||
* honours it: shown read-only and stored on the transaction, exactly as a bolt11
|
||||
* invoice's description is.
|
||||
*/
|
||||
memo?: string
|
||||
}
|
||||
|
||||
@@ -397,10 +404,10 @@ const navigateWithIncomingData = async function (
|
||||
screen: 'TransferOnchain',
|
||||
params: {
|
||||
address: btc.address,
|
||||
// BIP21 amount and label are HINTS from the payee. They pre-fill the
|
||||
// screen; the user stays free to change both, and the mint prices the
|
||||
// payment from what is actually confirmed.
|
||||
// The BIP21 amount is a HINT: it pre-fills the screen, the user stays free
|
||||
// to change it, and the mint prices the payment from what they confirm.
|
||||
amountSat: btc.amountSat,
|
||||
// The payee's own description, if the URI carried one. Read-only.
|
||||
memo: btc.memo,
|
||||
unit,
|
||||
mintUrl
|
||||
|
||||
Reference in New Issue
Block a user