aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-24 14:12:46 -0700
committerAdam Soltys <[email protected]>2026-06-24 14:12:46 -0700
commit3463af1d81c2712d657bbf30ecba98ffe5873729 (patch)
tree897aa78d3aa3f9227b6a3de00132ded16607033a /src
parent1a92d81b792f9e6d2ecb284aab979985a36d34c7 (diff)
downloadcoinosv3-3463af1d81c2712d657bbf30ecba98ffe5873729.tar.gz
coinosv3-3463af1d81c2712d657bbf30ecba98ffe5873729.zip
Fee-aware gift minimum; move gift entrypoint to Send page
Minimum: the flat 546-sat floor is replaced by a fee-aware minimum (dust + one claim fee of headroom, floored at 546) via giftMinimum(), so the recipient clears dust comfortably even if fees rise before they claim — e.g. ~1000 sats at 5 sat/vB, ~7300 at 50. The create form shows the live minimum and rejects below it; buildClaimTx keeps the hard 294-sat dust guard as a final backstop (claim fails rather than handing over dust). UI: the gift entrypoint moves from Settings to a "Gift some Bitcoin" link on the Send page, opening the gift view as a send sub-view with a back button. New strings translated across all 19 locales. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/app.js33
-rw-r--r--src/i18n.js3
-rw-r--r--src/locales/ar.json5
-rw-r--r--src/locales/bn.json5
-rw-r--r--src/locales/de.json5
-rw-r--r--src/locales/es.json5
-rw-r--r--src/locales/fr.json5
-rw-r--r--src/locales/hi.json5
-rw-r--r--src/locales/id.json5
-rw-r--r--src/locales/ja.json5
-rw-r--r--src/locales/ko.json5
-rw-r--r--src/locales/mr.json5
-rw-r--r--src/locales/pt.json5
-rw-r--r--src/locales/ru.json5
-rw-r--r--src/locales/sw.json5
-rw-r--r--src/locales/ta.json5
-rw-r--r--src/locales/te.json5
-rw-r--r--src/locales/tr.json5
-rw-r--r--src/locales/ur.json5
-rw-r--r--src/locales/vi.json5
-rw-r--r--src/locales/zh.json5
-rw-r--r--src/wallet.js12
22 files changed, 96 insertions, 47 deletions
diff --git a/src/app.js b/src/app.js
index 07fe347..98b5d3a 100644
--- a/src/app.js
+++ b/src/app.js
@@ -4,7 +4,7 @@
// which rebuilds the active screen. Text inputs write back into `ui` on `input`
// (without re-rendering) so their values survive structural re-renders.
-import { Wallet, newMnemonic, isValidMnemonic, utxoId, previewGift, buildClaimTx } from './wallet.js';
+import { Wallet, newMnemonic, isValidMnemonic, utxoId, previewGift, buildClaimTx, giftMinimum } from './wallet.js';
import { qrSvg } from './qr.js';
import { scanQr } from './scan.js';
import { getSyncConfig, setSyncConfig } from './nostr.js';
@@ -35,7 +35,8 @@ const ui = {
passphrase: '',
showPass: false,
revealShown: false, // recovery phrase unmasked on the Backup tab (after the warning)
- giftAmount: '', // gift-create amount input (Settings)
+ giftMode: false, // gift sub-view active on the Send page
+ giftAmount: '', // gift-create amount input
giftCode: null, // last-created gift PSBT code
giftError: '',
revokeId: null, // outpoint of a gift being revoked (confirm state)
@@ -612,6 +613,7 @@ function lock() {
ui.passphrase = '';
ui.confirm = [];
ui.revealShown = false;
+ ui.giftMode = false;
ui.giftAmount = '';
ui.giftCode = null;
ui.giftError = '';
@@ -693,7 +695,6 @@ function settingsTab() {
wallet.scanning ? t('scanning') : t('rescanWallet'))
),
explorerCard(),
- giftCard(),
syncCard(),
h(
'div',
@@ -709,10 +710,14 @@ function settingsTab() {
function giftUrl() {
return `${location.origin}/#gift=${ui.giftCode}`;
}
+function giftRate() {
+ return (wallet.feeRates && wallet.feeRates.halfHourFee) || 5;
+}
function createGiftLink() {
+ const rate = giftRate();
+ const min = giftMinimum(rate);
const amt = Math.round(Number(ui.giftAmount));
- if (!amt || amt < 546) { ui.giftError = t('giftAmountInvalid'); render(); return; }
- const rate = (wallet.feeRates && wallet.feeRates.halfHourFee) || 5;
+ if (!amt || amt < min) { ui.giftError = t('giftAmountInvalid', { n: fmtAmount(min) + ' ' + unitLabel() }); render(); return; }
try {
ui.giftCode = wallet.createGift(amt, rate).code;
ui.giftError = '';
@@ -740,10 +745,11 @@ function giftCard() {
)
: h('div', { class: 'col gap6' },
h('div', { class: 'input-group' },
- h('input', { type: 'number', min: '546', inputmode: 'numeric', placeholder: t('giftAmountLabel'),
+ h('input', { type: 'number', min: String(giftMinimum(giftRate())), inputmode: 'numeric', placeholder: t('giftAmountLabel'),
value: ui.giftAmount, onInput: (e) => (ui.giftAmount = e.target.value) }),
h('span', { class: 'small muted', style: 'align-self:center' }, unitLabel())
),
+ h('div', { class: 'small faint' }, t('giftMinNote', { n: fmtAmount(giftMinimum(giftRate())) + ' ' + unitLabel() })),
ui.giftError && h('div', { class: 'notice err' }, ui.giftError),
h('button', { class: 'btn-block', onClick: createGiftLink }, t('giftLinkReveal'))
),
@@ -1073,6 +1079,7 @@ function tabsBar() {
ui.revealShown = false; // re-mask the recovery phrase whenever tabs change
ui.txDetail = null; // back to the history list when leaving/returning
ui.bump = null;
+ ui.giftMode = false;
render();
})
)
@@ -1130,9 +1137,20 @@ function sendTab() {
if (ui.sendResult) return sendResultView();
if (ui.broadcastTx) return broadcastConfirmView();
if (ui.draft) return reviewView();
+ if (ui.giftMode) return giftView();
return sendForm();
}
+// The gift UI as a send-page sub-view (entered from a link on the send form).
+function giftView() {
+ return h(
+ 'div',
+ { class: 'col', style: 'gap:12px' },
+ giftCard(),
+ h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.giftMode = false; ui.giftCode = null; ui.giftError = ''; ui.revokeId = null; render(); } }, t('back'))
+ );
+}
+
// QR scanning is only possible in a secure context with a camera.
const canScan = () =>
typeof navigator !== 'undefined' && !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
@@ -1480,7 +1498,8 @@ function sendForm() {
),
coinControl(),
ui.sendError && h('div', { class: 'notice err' }, ui.sendError),
- h('button', { class: 'btn-primary btn-block', onClick: reviewSend }, t('reviewTx'))
+ h('button', { class: 'btn-primary btn-block', onClick: reviewSend }, t('reviewTx')),
+ h('button', { class: 'linklike small', style: 'align-self:center;margin-top:2px', onClick: () => { ui.giftMode = true; ui.sendError = ''; render(); } }, t('giftLink'))
);
}
diff --git a/src/i18n.js b/src/i18n.js
index 57475dc..abb9015 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -151,7 +151,8 @@ const STR = {
giftLinkWarn: '⚠ Anyone who opens this link can claim the amount, so share it only with the person you are gifting. Keep amounts small.',
giftLinkReveal: 'Create gift link',
giftAmountLabel: 'Amount to gift',
- giftAmountInvalid: 'Enter a valid amount.',
+ giftAmountInvalid: 'Enter at least {n}.',
+ giftMinNote: 'Minimum {n} at current fees, so it clears dust when claimed.',
giftAnother: 'Create another',
giftReserved: 'Unclaimed gift links ({n})',
giftReclaim: 'Reclaim',
diff --git a/src/locales/ar.json b/src/locales/ar.json
index 923e8d2..76843bc 100644
--- a/src/locales/ar.json
+++ b/src/locales/ar.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "وقّع مبلغاً مسبقاً كرابط. من يفتحه يطالب بعملات Bitcoin في محفظة جديدة تماماً يتحكم بها وحده.",
"giftLinkWarn": "⚠ أي شخص يفتح هذا الرابط يمكنه المطالبة بالمبلغ، لذا شاركه فقط مع الشخص الذي تهديه إياه. أبقِ المبالغ صغيرة.",
"giftAmountLabel": "المبلغ المراد إهداؤه",
- "giftAmountInvalid": "أدخل مبلغاً صحيحاً.",
+ "giftAmountInvalid": "أدخل {n} على الأقل.",
"giftAnother": "إنشاء آخر",
"giftReserved": "روابط الهدايا غير المُطالب بها ({n})",
"claimBody": "طالب بها في محفظة جديدة تماماً تتحكم بها وحدك.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "الاسترجاع يحرر هذه العملة لدفعتك التالية، لكن يظل بالإمكان المطالبة بالرابط حتى تنفقها. هل تدفع رسوم الشبكة لإلغائه الآن بدلاً من ذلك؟",
"giftReclaimed": "تم استرجاع العملة",
"giftRevokeConfirm": "إلغاء هذه الهدية الآن؟ يعيد ذلك العملة إلى محفظتك ويعطّل الرابط.",
- "giftReclaimedTag": "لا يزال قابلاً للمطالبة"
+ "giftReclaimedTag": "لا يزال قابلاً للمطالبة",
+ "giftMinNote": "الحد الأدنى {n} بالرسوم الحالية، ليتجاوز الغبار عند المطالبة."
} \ No newline at end of file
diff --git a/src/locales/bn.json b/src/locales/bn.json
index 04f87a5..27d657b 100644
--- a/src/locales/bn.json
+++ b/src/locales/bn.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "একটি পরিমাণ লিঙ্ক হিসেবে আগে থেকে সই করুন। যে এটি খুলবে সে Bitcoin-টি একটি একদম নতুন ওয়ালেটে দাবি করে, যা কেবল সে-ই নিয়ন্ত্রণ করে।",
"giftLinkWarn": "⚠ যে কেউ এই লিঙ্ক খুললে পরিমাণটি দাবি করতে পারে, তাই কেবল যাকে উপহার দিচ্ছেন তার সাথেই এটি শেয়ার করুন। পরিমাণ কম রাখুন।",
"giftAmountLabel": "উপহারের পরিমাণ",
- "giftAmountInvalid": "একটি সঠিক পরিমাণ লিখুন।",
+ "giftAmountInvalid": "কমপক্ষে {n} লিখুন।",
"giftAnother": "আরেকটি তৈরি করুন",
"giftReserved": "দাবিহীন উপহার লিঙ্ক ({n})",
"claimBody": "এটি একটি একদম নতুন ওয়ালেটে দাবি করুন, যা কেবল আপনিই নিয়ন্ত্রণ করেন।",
@@ -169,5 +169,6 @@
"giftReclaimPrompt": "ফেরত নিলে এই কয়েনটি আপনার পরবর্তী পেমেন্টের জন্য মুক্ত হয়, তবে আপনি খরচ না করা পর্যন্ত লিঙ্কটি দাবিযোগ্য থাকে। বদলে নেটওয়ার্ক ফি দিয়ে এখনই বাতিল করবেন?",
"giftReclaimed": "কয়েন ফেরত নেওয়া হয়েছে",
"giftRevokeConfirm": "এই উপহার এখনই বাতিল করবেন? এটি কয়েনটি আপনার ওয়ালেটে ফেরত পাঠায় এবং লিঙ্কটি নিষ্ক্রিয় করে।",
- "giftReclaimedTag": "এখনও দাবিযোগ্য"
+ "giftReclaimedTag": "এখনও দাবিযোগ্য",
+ "giftMinNote": "বর্তমান ফিতে কমপক্ষে {n}, যাতে দাবি করার সময় এটি ডাস্ট ছাড়িয়ে যায়।"
} \ No newline at end of file
diff --git a/src/locales/de.json b/src/locales/de.json
index ef9346f..83968e3 100644
--- a/src/locales/de.json
+++ b/src/locales/de.json
@@ -157,7 +157,7 @@
"giftLinkReveal": "Geschenk-Link erstellen",
"copyLink": "Link kopieren",
"giftAmountLabel": "Zu verschenkender Betrag",
- "giftAmountInvalid": "Gib einen gültigen Betrag ein.",
+ "giftAmountInvalid": "Gib mindestens {n} ein.",
"giftAnother": "Weiteres erstellen",
"giftReserved": "Nicht eingelöste Geschenk-Links ({n})",
"claimBody": "Beanspruche es in einer brandneuen Wallet, die nur du selbst kontrollierst.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Zurückholen gibt diese Münze für deine nächste Zahlung frei, aber der Link bleibt einlösbar, bis du sie ausgibst. Stattdessen eine Netzwerkgebühr zahlen, um ihn jetzt zu widerrufen?",
"giftReclaimed": "Münze zurückgeholt",
"giftRevokeConfirm": "Dieses Geschenk jetzt widerrufen? Die Münze geht zurück in deine Wallet und der Link wird deaktiviert.",
- "giftReclaimedTag": "noch einlösbar"
+ "giftReclaimedTag": "noch einlösbar",
+ "giftMinNote": "Mindestens {n} bei aktuellen Gebühren, damit es beim Einlösen über dem Dust-Limit liegt."
} \ No newline at end of file
diff --git a/src/locales/es.json b/src/locales/es.json
index 4c5a214..c3c77fe 100644
--- a/src/locales/es.json
+++ b/src/locales/es.json
@@ -157,7 +157,7 @@
"giftLinkReveal": "Crear enlace de regalo",
"copyLink": "Copiar enlace",
"giftAmountLabel": "Importe a regalar",
- "giftAmountInvalid": "Introduce un importe válido.",
+ "giftAmountInvalid": "Introduce al menos {n}.",
"giftAnother": "Crear otro",
"giftReserved": "Enlaces de regalo sin reclamar ({n})",
"claimBody": "Reclámalo en una billetera totalmente nueva que solo tú controlas.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Reclamar libera esta moneda para tu próximo pago, pero el enlace seguirá siendo reclamable hasta que la gastes. ¿Pagar una comisión de red para revocarlo ahora mismo?",
"giftReclaimed": "Moneda reclamada",
"giftRevokeConfirm": "¿Revocar este regalo ahora? Esto devuelve la moneda a tu monedero y desactiva el enlace.",
- "giftReclaimedTag": "aún reclamable"
+ "giftReclaimedTag": "aún reclamable",
+ "giftMinNote": "Mínimo {n} con las comisiones actuales, para que supere el polvo al reclamarse."
} \ No newline at end of file
diff --git a/src/locales/fr.json b/src/locales/fr.json
index d4c100b..4a22eee 100644
--- a/src/locales/fr.json
+++ b/src/locales/fr.json
@@ -157,7 +157,7 @@
"giftLinkReveal": "Créer le lien cadeau",
"copyLink": "Copier le lien",
"giftAmountLabel": "Montant à offrir",
- "giftAmountInvalid": "Saisissez un montant valide.",
+ "giftAmountInvalid": "Saisissez au moins {n}.",
"giftAnother": "En créer un autre",
"giftReserved": "Liens cadeaux non réclamés ({n})",
"claimBody": "Récupérez-les dans un tout nouveau portefeuille que vous seul contrôlez.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Récupérer libère cette pièce pour votre prochain paiement, mais le lien reste réclamable jusqu’à ce que vous la dépensiez. Payer des frais de réseau pour le révoquer tout de suite ?",
"giftReclaimed": "Pièce récupérée",
"giftRevokeConfirm": "Révoquer ce cadeau maintenant ? La pièce revient dans votre portefeuille et le lien est désactivé.",
- "giftReclaimedTag": "encore réclamable"
+ "giftReclaimedTag": "encore réclamable",
+ "giftMinNote": "Minimum {n} aux frais actuels, pour dépasser la poussière lors de la réclamation."
} \ No newline at end of file
diff --git a/src/locales/hi.json b/src/locales/hi.json
index 880841d..5b88673 100644
--- a/src/locales/hi.json
+++ b/src/locales/hi.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "एक राशि को लिंक के रूप में पहले से साइन करें। जो भी इसे खोलेगा, वह Bitcoin को एक बिल्कुल नए वॉलेट में प्राप्त कर लेगा जिसे केवल वही नियंत्रित करता है।",
"giftLinkWarn": "⚠ जो भी इस लिंक को खोलेगा वह राशि प्राप्त कर सकता है, इसलिए इसे केवल उसी व्यक्ति के साथ साझा करें जिसे आप उपहार दे रहे हैं। राशि कम रखें।",
"giftAmountLabel": "उपहार में देने की राशि",
- "giftAmountInvalid": "एक मान्य राशि दर्ज करें।",
+ "giftAmountInvalid": "कम से कम {n} दर्ज करें।",
"giftAnother": "एक और बनाएँ",
"giftReserved": "बिना दावे वाले उपहार लिंक ({n})",
"claimBody": "इसे एक बिल्कुल नए वॉलेट में प्राप्त करें जिसे केवल आप नियंत्रित करते हैं।",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "वापस लेने से यह सिक्का आपके अगले भुगतान के लिए मुक्त हो जाता है, लेकिन जब तक आप इसे खर्च नहीं करते, लिंक दावा-योग्य रहता है। इसके बजाय अभी रद्द करने के लिए नेटवर्क शुल्क चुकाएं?",
"giftReclaimed": "सिक्का वापस लिया गया",
"giftRevokeConfirm": "इस उपहार को अभी रद्द करें? यह सिक्का आपके वॉलेट में वापस भेजता है और लिंक को निष्क्रिय कर देता है।",
- "giftReclaimedTag": "अब भी दावा-योग्य"
+ "giftReclaimedTag": "अब भी दावा-योग्य",
+ "giftMinNote": "मौजूदा शुल्क पर कम से कम {n}, ताकि दावा करते समय यह डस्ट से ऊपर रहे।"
} \ No newline at end of file
diff --git a/src/locales/id.json b/src/locales/id.json
index 614b355..31d324f 100644
--- a/src/locales/id.json
+++ b/src/locales/id.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "Tandatangani sejumlah dana sebagai tautan. Siapa pun yang membukanya mengklaim Bitcoin itu ke dompet baru yang hanya dia kendalikan.",
"giftLinkWarn": "⚠ Siapa pun yang membuka tautan ini bisa mengklaim jumlahnya, jadi bagikan hanya kepada orang yang Anda beri hadiah. Jaga jumlahnya tetap kecil.",
"giftAmountLabel": "Jumlah yang dihadiahkan",
- "giftAmountInvalid": "Masukkan jumlah yang valid.",
+ "giftAmountInvalid": "Masukkan minimal {n}.",
"giftAnother": "Buat lagi",
"giftReserved": "Tautan hadiah belum diklaim ({n})",
"claimBody": "Klaim ke dompet baru yang hanya Anda kendalikan.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Menarik kembali membebaskan koin ini untuk pembayaran berikutnya, tetapi tautan tetap bisa diklaim sampai Anda membelanjakannya. Bayar biaya jaringan untuk mencabutnya sekarang?",
"giftReclaimed": "Koin ditarik kembali",
"giftRevokeConfirm": "Cabut hadiah ini sekarang? Ini mengembalikan koin ke dompet Anda dan menonaktifkan tautannya.",
- "giftReclaimedTag": "masih bisa diklaim"
+ "giftReclaimedTag": "masih bisa diklaim",
+ "giftMinNote": "Minimal {n} pada biaya saat ini, agar melampaui dust saat diklaim."
} \ No newline at end of file
diff --git a/src/locales/ja.json b/src/locales/ja.json
index b0ab956..35b91a8 100644
--- a/src/locales/ja.json
+++ b/src/locales/ja.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "金額をリンクとして事前署名します。リンクを開いた人が、その人だけが管理できる真新しいウォレットに Bitcoin を受け取ります。",
"giftLinkWarn": "⚠ このリンクを開いた人は誰でもその金額を受け取れるので、贈る相手とだけ共有してください。金額は少なめにしましょう。",
"giftAmountLabel": "贈る金額",
- "giftAmountInvalid": "有効な金額を入力してください。",
+ "giftAmountInvalid": "{n} 以上を入力してください。",
"giftAnother": "もう一つ作成",
"giftReserved": "未請求のギフトリンク({n})",
"claimBody": "あなただけが管理できる真新しいウォレットに受け取りましょう。",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "取り戻すと次の支払いにこのコインを使えますが、使うまでリンクは請求可能なままです。代わりにネットワーク手数料を払って今すぐ取り消しますか?",
"giftReclaimed": "コインを取り戻しました",
"giftRevokeConfirm": "このギフトを今すぐ取り消しますか?コインがウォレットに戻り、リンクが無効になります。",
- "giftReclaimedTag": "まだ請求可能"
+ "giftReclaimedTag": "まだ請求可能",
+ "giftMinNote": "現在の手数料で最低 {n}。請求時にダストを上回ります。"
} \ No newline at end of file
diff --git a/src/locales/ko.json b/src/locales/ko.json
index 21e6ad7..6f87ae7 100644
--- a/src/locales/ko.json
+++ b/src/locales/ko.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "금액을 링크로 미리 서명하세요. 링크를 여는 사람은 그 Bitcoin을 자신만 통제하는 완전히 새로운 지갑으로 받게 됩니다.",
"giftLinkWarn": "⚠ 이 링크를 여는 사람은 누구나 금액을 받을 수 있으니, 선물할 상대에게만 공유하세요. 금액은 적게 유지하세요.",
"giftAmountLabel": "선물할 금액",
- "giftAmountInvalid": "올바른 금액을 입력하세요.",
+ "giftAmountInvalid": "최소 {n}을(를) 입력하세요.",
"giftAnother": "또 만들기",
"giftReserved": "청구되지 않은 선물 링크 ({n})",
"claimBody": "자신만 통제하는 완전히 새로운 지갑으로 받으세요.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "회수하면 이 코인을 다음 결제에 쓸 수 있지만, 코인을 쓰기 전까지 링크는 청구 가능합니다. 대신 네트워크 수수료를 내고 지금 바로 취소할까요?",
"giftReclaimed": "코인 회수됨",
"giftRevokeConfirm": "이 선물을 지금 취소할까요? 코인이 지갑으로 돌아가고 링크가 비활성화됩니다.",
- "giftReclaimedTag": "아직 청구 가능"
+ "giftReclaimedTag": "아직 청구 가능",
+ "giftMinNote": "현재 수수료 기준 최소 {n}, 청구 시 더스트를 넘도록."
} \ No newline at end of file
diff --git a/src/locales/mr.json b/src/locales/mr.json
index 01a24b4..a4c864e 100644
--- a/src/locales/mr.json
+++ b/src/locales/mr.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "एखादी रक्कम लिंक म्हणून आधीच स्वाक्षरित करा. ती उघडणारा कोणीही ते Bitcoin फक्त त्याच्याच नियंत्रणातील एका नव्या कोऱ्या वॉलेटमध्ये घेतो.",
"giftLinkWarn": "⚠ ही लिंक उघडणारा कोणीही ती रक्कम घेऊ शकतो, म्हणून ज्याला भेट देत आहात फक्त त्याच्यासोबतच ती शेअर करा. रक्कम कमी ठेवा.",
"giftAmountLabel": "भेट देण्याची रक्कम",
- "giftAmountInvalid": "वैध रक्कम टाका.",
+ "giftAmountInvalid": "किमान {n} प्रविष्ट करा.",
"giftAnother": "आणखी एक तयार करा",
"giftReserved": "दावा न केलेल्या भेट लिंक ({n})",
"claimBody": "ते फक्त तुमच्याच नियंत्रणातील एका नव्या कोऱ्या वॉलेटमध्ये घ्या.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "परत घेतल्याने हे नाणे तुमच्या पुढील पेमेंटसाठी मोकळे होते, पण तुम्ही ते खर्च करेपर्यंत लिंक दावायोग्य राहते. त्याऐवजी आत्ताच रद्द करण्यासाठी नेटवर्क शुल्क भरायचे?",
"giftReclaimed": "नाणे परत घेतले",
"giftRevokeConfirm": "ही भेट आत्ता रद्द करायची? हे नाणे तुमच्या वॉलेटमध्ये परत पाठवते आणि लिंक निष्क्रिय करते.",
- "giftReclaimedTag": "अजूनही दावायोग्य"
+ "giftReclaimedTag": "अजूनही दावायोग्य",
+ "giftMinNote": "सध्याच्या शुल्कावर किमान {n}, जेणेकरून दावा करताना ते डस्टपेक्षा जास्त असेल."
} \ No newline at end of file
diff --git a/src/locales/pt.json b/src/locales/pt.json
index 3865e98..0710d94 100644
--- a/src/locales/pt.json
+++ b/src/locales/pt.json
@@ -157,7 +157,7 @@
"giftLinkReveal": "Criar link de presente",
"copyLink": "Copiar link",
"giftAmountLabel": "Valor a presentear",
- "giftAmountInvalid": "Digite um valor válido.",
+ "giftAmountInvalid": "Insira pelo menos {n}.",
"giftAnother": "Criar outro",
"giftReserved": "Links de presente não resgatados ({n})",
"claimBody": "Resgate para uma carteira novinha que só você controla.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Recuperar libera esta moeda para o seu próximo pagamento, mas o link continua resgatável até você gastá-la. Pagar uma taxa de rede para revogá-lo agora?",
"giftReclaimed": "Moeda recuperada",
"giftRevokeConfirm": "Revogar este presente agora? Isso devolve a moeda à sua carteira e desativa o link.",
- "giftReclaimedTag": "ainda resgatável"
+ "giftReclaimedTag": "ainda resgatável",
+ "giftMinNote": "Mínimo {n} com as taxas atuais, para superar a poeira ao ser resgatado."
} \ No newline at end of file
diff --git a/src/locales/ru.json b/src/locales/ru.json
index cc3910a..0654f21 100644
--- a/src/locales/ru.json
+++ b/src/locales/ru.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "Заранее подпишите сумму в виде ссылки. Тот, кто откроет её, получит Bitcoin в совершенно новый кошелёк, которым управляет только он.",
"giftLinkWarn": "⚠ Любой, кто откроет эту ссылку, может получить эту сумму, поэтому делитесь ею только с тем, кому дарите. Держите суммы небольшими.",
"giftAmountLabel": "Сумма подарка",
- "giftAmountInvalid": "Введите корректную сумму.",
+ "giftAmountInvalid": "Введите не менее {n}.",
"giftAnother": "Создать ещё один",
"giftReserved": "Невостребованные подарочные ссылки ({n})",
"claimBody": "Получите его в совершенно новый кошелёк, которым управляете только вы.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Возврат освобождает монету для следующего платежа, но ссылку можно получить, пока вы её не потратите. Заплатить комиссию сети, чтобы отозвать прямо сейчас?",
"giftReclaimed": "Монета возвращена",
"giftRevokeConfirm": "Отозвать этот подарок сейчас? Монета вернётся в ваш кошелёк, а ссылка будет отключена.",
- "giftReclaimedTag": "ещё можно получить"
+ "giftReclaimedTag": "ещё можно получить",
+ "giftMinNote": "Минимум {n} при текущих комиссиях, чтобы при получении сумма была выше пыли."
} \ No newline at end of file
diff --git a/src/locales/sw.json b/src/locales/sw.json
index 05864a7..0e41dcb 100644
--- a/src/locales/sw.json
+++ b/src/locales/sw.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "Tia saini kiasi mapema kama kiungo. Yeyote anayekifungua hudai Bitcoin kwenye pochi mpya kabisa anayoidhibiti yeye pekee.",
"giftLinkWarn": "⚠ Yeyote anayefungua kiungo hiki anaweza kudai kiasi hicho, kwa hivyo kishiriki tu na mtu unayempa zawadi. Weka kiasi kidogo.",
"giftAmountLabel": "Kiasi cha kutoa zawadi",
- "giftAmountInvalid": "Ingiza kiasi sahihi.",
+ "giftAmountInvalid": "Weka angalau {n}.",
"giftAnother": "Tengeneza nyingine",
"giftReserved": "Viungo vya zawadi visivyodaiwa ({n})",
"claimBody": "Idai kwenye pochi mpya kabisa unayoidhibiti wewe pekee.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Kurudisha hufungua sarafu hii kwa malipo yako yajayo, lakini kiungo kinabaki kinaweza kudaiwa hadi uitumie. Badala yake ulipe ada ya mtandao kuibatilisha sasa hivi?",
"giftReclaimed": "Sarafu imerudishwa",
"giftRevokeConfirm": "Batilisha zawadi hii sasa? Hii inarudisha sarafu kwenye pochi yako na kuzima kiungo.",
- "giftReclaimedTag": "bado inaweza kudaiwa"
+ "giftReclaimedTag": "bado inaweza kudaiwa",
+ "giftMinNote": "Kima cha chini {n} kwa ada za sasa, ili kuzidi vumbi inapodaiwa."
} \ No newline at end of file
diff --git a/src/locales/ta.json b/src/locales/ta.json
index e94aa7e..2b9df36 100644
--- a/src/locales/ta.json
+++ b/src/locales/ta.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "ஒரு தொகையை இணைப்பாக முன்கூட்டியே கையொப்பமிடுங்கள். இதைத் திறப்பவர், அவர்கள் மட்டுமே கட்டுப்படுத்தும் புத்தம்புதிய வாலட்டிற்குள் Bitcoin-ஐ உரிமை கொள்வார்கள்.",
"giftLinkWarn": "⚠ இந்த இணைப்பைத் திறக்கும் எவரும் தொகையை உரிமை கொள்ளலாம், எனவே நீங்கள் பரிசளிக்கும் நபருடன் மட்டுமே இதைப் பகிரவும். தொகையைக் குறைவாக வைத்திருங்கள்.",
"giftAmountLabel": "பரிசளிக்கும் தொகை",
- "giftAmountInvalid": "சரியான தொகையை உள்ளிடவும்.",
+ "giftAmountInvalid": "குறைந்தது {n} உள்ளிடவும்.",
"giftAnother": "மற்றொன்றை உருவாக்கு",
"giftReserved": "கோரப்படாத பரிசு இணைப்புகள் ({n})",
"claimBody": "நீங்கள் மட்டுமே கட்டுப்படுத்தும் புத்தம்புதிய வாலட்டிற்குள் இதை உரிமை கொள்ளுங்கள்.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "திரும்பப் பெறுவது இந்த நாணயத்தை உங்கள் அடுத்த கட்டணத்திற்கு விடுவிக்கும், ஆனால் நீங்கள் அதைச் செலவழிக்கும் வரை இணைப்பு கோரத்தக்கதாக இருக்கும். அதற்குப் பதிலாக இப்போதே ரத்து செய்ய நெட்வொர்க் கட்டணம் செலுத்தவா?",
"giftReclaimed": "நாணயம் திரும்பப் பெறப்பட்டது",
"giftRevokeConfirm": "இந்த பரிசை இப்போதே ரத்து செய்யவா? இது நாணயத்தை உங்கள் வாலெட்டுக்குத் திருப்பி, இணைப்பை முடக்கும்.",
- "giftReclaimedTag": "இன்னும் கோரத்தக்கது"
+ "giftReclaimedTag": "இன்னும் கோரத்தக்கது",
+ "giftMinNote": "தற்போதைய கட்டணத்தில் குறைந்தது {n}, கோரும்போது அது டஸ்ட்டைத் தாண்டும்."
} \ No newline at end of file
diff --git a/src/locales/te.json b/src/locales/te.json
index 2334a2d..99525bd 100644
--- a/src/locales/te.json
+++ b/src/locales/te.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "ఒక మొత్తాన్ని ముందుగా సంతకం చేసి లింక్‌గా ఇవ్వండి. దాన్ని తెరిచినవారు ఆ Bitcoinను తాము మాత్రమే నియంత్రించే సరికొత్త వాలెట్‌లోకి క్లెయిమ్ చేసుకుంటారు.",
"giftLinkWarn": "⚠ ఈ లింక్ తెరిచిన ఎవరైనా ఆ మొత్తాన్ని క్లెయిమ్ చేయగలరు, కాబట్టి మీరు బహుమతి ఇస్తున్న వ్యక్తికి మాత్రమే దీన్ని పంచుకోండి. మొత్తాలను తక్కువగా ఉంచండి.",
"giftAmountLabel": "బహుమతిగా ఇచ్చే మొత్తం",
- "giftAmountInvalid": "సరైన మొత్తాన్ని నమోదు చేయండి.",
+ "giftAmountInvalid": "కనీసం {n} నమోదు చేయండి.",
"giftAnother": "మరొకటి సృష్టించు",
"giftReserved": "దావా చేయని బహుమతి లింకులు ({n})",
"claimBody": "మీరు మాత్రమే నియంత్రించే సరికొత్త వాలెట్‌లోకి దాన్ని క్లెయిమ్ చేసుకోండి.",
@@ -169,5 +169,6 @@
"giftReclaimPrompt": "తిరిగి తీసుకోవడం ఈ నాణేన్ని మీ తదుపరి చెల్లింపు కోసం విడుదల చేస్తుంది, కానీ మీరు ఖర్చు చేసే వరకు లింక్ క్లెయిమ్ చేయదగినదిగా ఉంటుంది. బదులుగా ఇప్పుడే రద్దు చేయడానికి నెట్‌వర్క్ ఫీజు చెల్లించాలా?",
"giftReclaimed": "నాణెం తిరిగి తీసుకోబడింది",
"giftRevokeConfirm": "ఈ బహుమతిని ఇప్పుడే రద్దు చేయాలా? ఇది నాణేన్ని మీ వాలెట్‌కు తిరిగి పంపి, లింక్‌ను నిష్క్రియం చేస్తుంది.",
- "giftReclaimedTag": "ఇంకా క్లెయిమ్ చేయదగినది"
+ "giftReclaimedTag": "ఇంకా క్లెయిమ్ చేయదగినది",
+ "giftMinNote": "ప్రస్తుత ఫీజుల వద్ద కనీసం {n}, తద్వారా క్లెయిమ్ చేసేటప్పుడు అది డస్ట్‌ను దాటుతుంది."
} \ No newline at end of file
diff --git a/src/locales/tr.json b/src/locales/tr.json
index d4331a4..44a05ce 100644
--- a/src/locales/tr.json
+++ b/src/locales/tr.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "Bir tutarı önceden imzalayıp bağlantı olarak verin. Bağlantıyı açan, Bitcoin’i yalnızca kendi kontrolündeki yepyeni bir cüzdana alır.",
"giftLinkWarn": "⚠ Bu bağlantıyı açan herkes tutarı talep edebilir, bu yüzden yalnızca hediye ettiğiniz kişiyle paylaşın. Tutarları küçük tutun.",
"giftAmountLabel": "Hediye edilecek tutar",
- "giftAmountInvalid": "Geçerli bir tutar girin.",
+ "giftAmountInvalid": "En az {n} girin.",
"giftAnother": "Bir tane daha oluştur",
"giftReserved": "Talep edilmemiş hediye bağlantıları ({n})",
"claimBody": "Yalnızca kendi kontrolünüzdeki yepyeni bir cüzdana alın.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Geri almak bu parayı bir sonraki ödemen için serbest bırakır, ancak sen harcayana kadar bağlantı talep edilebilir kalır. Bunun yerine şimdi iptal etmek için ağ ücreti ödensin mi?",
"giftReclaimed": "Para geri alındı",
"giftRevokeConfirm": "Bu hediye şimdi iptal edilsin mi? Bu, parayı cüzdanınıza geri gönderir ve bağlantıyı devre dışı bırakır.",
- "giftReclaimedTag": "hâlâ talep edilebilir"
+ "giftReclaimedTag": "hâlâ talep edilebilir",
+ "giftMinNote": "Mevcut ücretlerde en az {n}, böylece talep edildiğinde tozu aşar."
} \ No newline at end of file
diff --git a/src/locales/ur.json b/src/locales/ur.json
index 0d523d6..ebc667e 100644
--- a/src/locales/ur.json
+++ b/src/locales/ur.json
@@ -157,7 +157,7 @@
"giftLinkReveal": "تحفہ لنک بنائیں",
"copyLink": "لنک کاپی کریں",
"giftAmountLabel": "تحفے کی رقم",
- "giftAmountInvalid": "درست رقم درج کریں۔",
+ "giftAmountInvalid": "کم از کم {n} درج کریں۔",
"giftAnother": "ایک اور بنائیں",
"giftReserved": "غیر دعویٰ شدہ تحفہ لنکس ({n})",
"claimBody": "اسے ایک بالکل نئے والیٹ میں وصول کریں جو صرف آپ کے کنٹرول میں ہو۔",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "واپس لینے سے یہ سکہ آپ کی اگلی ادائیگی کے لیے آزاد ہو جاتا ہے، لیکن جب تک آپ اسے خرچ نہیں کرتے لنک قابلِ وصول رہتا ہے۔ اس کے بجائے ابھی منسوخ کرنے کے لیے نیٹ ورک فیس ادا کریں؟",
"giftReclaimed": "سکہ واپس لے لیا گیا",
"giftRevokeConfirm": "اس تحفے کو ابھی منسوخ کریں؟ یہ سکہ آپ کے والیٹ میں واپس بھیجتا ہے اور لنک کو غیر فعال کر دیتا ہے۔",
- "giftReclaimedTag": "اب بھی قابلِ وصول"
+ "giftReclaimedTag": "اب بھی قابلِ وصول",
+ "giftMinNote": "موجودہ فیس پر کم از کم {n}، تاکہ وصول کرتے وقت یہ ڈسٹ سے اوپر رہے۔"
} \ No newline at end of file
diff --git a/src/locales/vi.json b/src/locales/vi.json
index 3e05446..b715777 100644
--- a/src/locales/vi.json
+++ b/src/locales/vi.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "Ký trước một số tiền thành một liên kết. Ai mở liên kết sẽ nhận số Bitcoin đó vào một ví hoàn toàn mới mà chỉ riêng họ kiểm soát.",
"giftLinkWarn": "⚠ Bất kỳ ai mở liên kết này đều có thể nhận số tiền, vì vậy chỉ chia sẻ với người bạn muốn tặng. Hãy giữ số tiền nhỏ.",
"giftAmountLabel": "Số tiền muốn tặng",
- "giftAmountInvalid": "Nhập một số tiền hợp lệ.",
+ "giftAmountInvalid": "Nhập tối thiểu {n}.",
"giftAnother": "Tạo cái khác",
"giftReserved": "Liên kết quà chưa nhận ({n})",
"claimBody": "Nhận nó vào một ví hoàn toàn mới mà chỉ riêng bạn kiểm soát.",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "Thu lại giải phóng đồng coin này cho lần thanh toán tới, nhưng liên kết vẫn có thể nhận được cho đến khi bạn tiêu nó. Trả phí mạng để thu hồi ngay bây giờ thay vào đó?",
"giftReclaimed": "Đã thu lại coin",
"giftRevokeConfirm": "Thu hồi quà này ngay? Việc này chuyển đồng coin về ví của bạn và vô hiệu hóa liên kết.",
- "giftReclaimedTag": "vẫn có thể nhận"
+ "giftReclaimedTag": "vẫn có thể nhận",
+ "giftMinNote": "Tối thiểu {n} ở mức phí hiện tại, để vượt mức bụi khi được nhận."
} \ No newline at end of file
diff --git a/src/locales/zh.json b/src/locales/zh.json
index c3a3d6e..074b4e8 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -155,7 +155,7 @@
"giftLinkDesc": "将一笔金额预签为一个链接。打开链接的人可将这笔 Bitcoin 领取到一个仅由他们自己掌控的全新钱包中。",
"giftLinkWarn": "⚠ 任何打开此链接的人都能领取这笔金额,所以请仅分享给你要赠送的对象。请保持金额较小。",
"giftAmountLabel": "赠送金额",
- "giftAmountInvalid": "请输入有效金额。",
+ "giftAmountInvalid": "至少输入 {n}。",
"giftAnother": "再创建一个",
"giftReserved": "未领取的礼物链接({n})",
"claimBody": "将它领取到一个仅由你自己掌控的全新钱包中。",
@@ -171,5 +171,6 @@
"giftReclaimPrompt": "收回会释放这笔币用于你的下一次付款,但在你花掉它之前链接仍可被领取。改为支付网络手续费立即撤销?",
"giftReclaimed": "已收回",
"giftRevokeConfirm": "立即撤销此礼物?这会将这笔币退回你的钱包并使链接失效。",
- "giftReclaimedTag": "仍可领取"
+ "giftReclaimedTag": "仍可领取",
+ "giftMinNote": "按当前手续费至少 {n},以便领取时高于尘埃。"
} \ No newline at end of file
diff --git a/src/wallet.js b/src/wallet.js
index ad890d3..39848e8 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -838,10 +838,12 @@ export class Wallet {
// direct to their own fresh address. Reserves the coin. Returns { code, ... }.
createGift(amountSats, feeRate) {
const gift = BigInt(Math.round(amountSats));
- if (gift < 546n) throw new Error('Gift amount is too small.');
const rate = Math.max(1, Math.round(feeRate));
const claimFee = BigInt(Math.ceil((11 + 68 + 31 * 2) * rate)); // claimer's 1-in 2-out tx
const DUST = 294n;
+ // Require dust + one claim fee of headroom so the recipient stays well above
+ // dust even if fees rise before they claim.
+ if (gift < BigInt(giftMinimum(rate))) throw new Error('Gift amount is too small.');
const need = gift + claimFee + DUST;
const coin = this.utxos
.filter((u) => u.confirmed && !this.isReserved(utxoId(u)))
@@ -1293,6 +1295,14 @@ export function utxoId(u) {
// base64url PSBT: one SIGHASH_SINGLE-signed input + the sender's change output.
// previewGift reports the room available to the claimer (before their fee);
// buildClaimTx adds the claimer's output and finalizes a broadcastable tx.
+// Smallest sensible gift at a given fee rate: dust + one claim fee of headroom
+// (floored at 546 sats), so the recipient clears dust even if fees climb.
+export function giftMinimum(feeRate) {
+ const rate = Math.max(1, Math.round(feeRate));
+ const claimFee = Math.ceil((11 + 68 + 31 * 2) * rate);
+ return Math.max(546, 294 + claimFee);
+}
+
export function previewGift(code) {
try {
const tx = btc.Transaction.fromPSBT(base64urlnopad.decode(code));