diff options
| author | Adam Soltys <[email protected]> | 2026-06-24 13:47:11 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-06-24 13:47:11 -0700 |
| commit | eb299830a2611a45e997bc729176ede81c5eead2 (patch) | |
| tree | cffe8b1f2ddc1e8b0698262b128c4f5d83acf9e9 /src | |
| parent | 7234a3de9e200f36accb754f62163f0bd5360832 (diff) | |
| download | coinosv3-eb299830a2611a45e997bc729176ede81c5eead2.tar.gz coinosv3-eb299830a2611a45e997bc729176ede81c5eead2.zip | |
Make gift Reclaim a real on-chain revoke
The old "Reclaim" only un-reserved the coin locally, so the gift link
stayed claimable. Replace it with "Revoke": a confirmed action that
sweeps the reserved coin back into the sender's own wallet at a high
fee (wallet.revokeGift), double-spending the gift's presigned input so
the link can't be claimed once it confirms. Races a simultaneous
claimer; if the gift was already claimed the broadcast just fails.
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.js | 35 | ||||
| -rw-r--r-- | src/i18n.js | 4 | ||||
| -rw-r--r-- | src/locales/ar.json | 8 | ||||
| -rw-r--r-- | src/locales/bn.json | 8 | ||||
| -rw-r--r-- | src/locales/de.json | 8 | ||||
| -rw-r--r-- | src/locales/es.json | 8 | ||||
| -rw-r--r-- | src/locales/fr.json | 6 | ||||
| -rw-r--r-- | src/locales/hi.json | 8 | ||||
| -rw-r--r-- | src/locales/id.json | 8 | ||||
| -rw-r--r-- | src/locales/ja.json | 8 | ||||
| -rw-r--r-- | src/locales/ko.json | 6 | ||||
| -rw-r--r-- | src/locales/mr.json | 8 | ||||
| -rw-r--r-- | src/locales/pt.json | 6 | ||||
| -rw-r--r-- | src/locales/ru.json | 8 | ||||
| -rw-r--r-- | src/locales/sw.json | 8 | ||||
| -rw-r--r-- | src/locales/ta.json | 6 | ||||
| -rw-r--r-- | src/locales/te.json | 8 | ||||
| -rw-r--r-- | src/locales/tr.json | 6 | ||||
| -rw-r--r-- | src/locales/ur.json | 8 | ||||
| -rw-r--r-- | src/locales/vi.json | 8 | ||||
| -rw-r--r-- | src/locales/zh.json | 6 | ||||
| -rw-r--r-- | src/wallet.js | 11 |
22 files changed, 136 insertions, 54 deletions
@@ -38,6 +38,7 @@ const ui = { giftAmount: '', // gift-create amount input (Settings) giftCode: null, // last-created gift PSBT code giftError: '', + revokeId: null, // outpoint of a gift being revoked (confirm state) claimCode: null, // gift code being claimed (opened from a #gift= link) claimedAmount: 0, claimError: '', @@ -614,6 +615,7 @@ function lock() { ui.giftAmount = ''; ui.giftCode = null; ui.giftError = ''; + ui.revokeId = null; ui.receiveSeenIndex = null; ui.txDetail = null; ui.broadcastTx = null; @@ -750,9 +752,21 @@ function giftCard() { h('span', { class: 'small muted' }, t('giftReserved', { n: active.length })), ...active.map((id) => { const u = wallet.utxos.find((x) => utxoId(x) === id); + const label = u ? fmtAmount(u.value) + ' ' + unitLabel() : id.slice(0, 12) + '…'; + if (ui.revokeId === id) { + return h('div', { class: 'col gap6' }, + h('span', { class: 'small muted' }, t('giftRevokeConfirm')), + h('div', { class: 'row gap6' }, + ui.busy + ? h('button', { class: 'btn-primary grow', disabled: true }, h('span', { class: 'spinner' })) + : h('button', { class: 'btn-primary grow', onClick: () => doRevoke(id) }, t('giftRevoke')), + h('button', { class: 'btn-ghost grow', onClick: () => { ui.revokeId = null; render(); } }, t('back')) + ) + ); + } return h('div', { class: 'row between' }, - h('span', { class: 'small mono' }, u ? fmtAmount(u.value) + ' ' + unitLabel() : id.slice(0, 12) + '…'), - h('button', { class: 'btn-sm', onClick: () => { wallet.unreserve(id); render(); } }, t('giftReclaim')) + h('span', { class: 'small mono' }, label), + h('button', { class: 'btn-sm', onClick: () => { ui.revokeId = id; render(); } }, t('giftRevoke')) ); }) ) @@ -760,6 +774,23 @@ function giftCard() { ); } +async function doRevoke(id) { + if (wallet.offline) { toast(t('scanOffline')); return; } + ui.busy = true; + render(); + try { + const rate = (wallet.feeRates && wallet.feeRates.fastestFee) || 10; + await wallet.revokeGift(id, rate); + ui.revokeId = null; + toast(t('giftRevoked')); + wallet.scan().catch(() => {}); + } catch (e) { + toast(e.message); + } + ui.busy = false; + render(); +} + // Block explorer / server selection: a preset (mempool.space, blockstream.info) // or a custom Esplora/electrs REST URL (e.g. your own node). function explorerCard() { diff --git a/src/i18n.js b/src/i18n.js index 017b6fa..b879a08 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -154,7 +154,9 @@ const STR = { giftAmountInvalid: 'Enter a valid amount.', giftAnother: 'Create another', giftReserved: '{n} coin set aside for unclaimed gifts', - giftReclaim: 'Reclaim', + giftRevoke: 'Revoke', + giftRevokeConfirm: 'Revoke this gift? This spends the coin back into your wallet and stops the link from working.', + giftRevoked: 'Gift revoked', copyLink: 'Copy link', claimBody: 'Claim it into a brand-new wallet that only you control.', claimBtn: 'Claim it', diff --git a/src/locales/ar.json b/src/locales/ar.json index 57f2ea6..bbac720 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "أدخل مبلغاً صحيحاً.", "giftAnother": "إنشاء آخر", "giftReserved": "{n} عملة مخصّصة للهدايا غير المُطالَب بها", - "giftReclaim": "استرجاع", "claimBody": "طالب بها في محفظة جديدة تماماً تتحكم بها وحدك.", "claimBtn": "طالب بها", "claimFailed": "تمت المطالبة بهذه الهدية بالفعل أو لم تعد متاحة.", "claimedTitle": "تمت المطالبة!", "claimedBody": "عملات Bitcoin الخاصة بك في طريقها إليك. احتفظ بنسخة احتياطية من عبارة الاسترداد لإبقائها آمنة.", "giftLinkReveal": "إنشاء رابط الإهداء", - "copyLink": "نسخ الرابط" -} + "copyLink": "نسخ الرابط", + "giftRevoke": "إلغاء", + "giftRevokeConfirm": "إلغاء هذه الهدية؟ يعيد ذلك العملة إلى محفظتك ويوقف عمل الرابط.", + "giftRevoked": "تم إلغاء الهدية" +}
\ No newline at end of file diff --git a/src/locales/bn.json b/src/locales/bn.json index 30b92a4..2c28359 100644 --- a/src/locales/bn.json +++ b/src/locales/bn.json @@ -158,10 +158,12 @@ "giftAmountInvalid": "একটি সঠিক পরিমাণ লিখুন।", "giftAnother": "আরেকটি তৈরি করুন", "giftReserved": "{n} কয়েন অদাবিকৃত উপহারের জন্য সরিয়ে রাখা হয়েছে", - "giftReclaim": "ফেরত নিন", "claimBody": "এটি একটি একদম নতুন ওয়ালেটে দাবি করুন, যা কেবল আপনিই নিয়ন্ত্রণ করেন।", "claimBtn": "দাবি করুন", "claimFailed": "এই উপহারটি আগেই দাবি করা হয়েছে অথবা আর পাওয়া যাচ্ছে না।", "claimedTitle": "দাবি করা হয়েছে!", - "claimedBody": "আপনার Bitcoin আসছে। এটি নিরাপদ রাখতে আপনার রিকভারি ফ্রেজ ব্যাকআপ করে নিন।" -} + "claimedBody": "আপনার Bitcoin আসছে। এটি নিরাপদ রাখতে আপনার রিকভারি ফ্রেজ ব্যাকআপ করে নিন।", + "giftRevoke": "বাতিল করুন", + "giftRevokeConfirm": "এই উপহার বাতিল করবেন? এটি কয়েনটি আপনার ওয়ালেটে ফেরত পাঠায় এবং লিঙ্কটি কাজ করা বন্ধ করে।", + "giftRevoked": "উপহার বাতিল হয়েছে" +}
\ No newline at end of file diff --git a/src/locales/de.json b/src/locales/de.json index 0b7b11e..8af72e0 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -160,10 +160,12 @@ "giftAmountInvalid": "Gib einen gültigen Betrag ein.", "giftAnother": "Weiteres erstellen", "giftReserved": "{n} Coin für unbeanspruchte Geschenke zurückgelegt", - "giftReclaim": "Zurückfordern", "claimBody": "Beanspruche es in einer brandneuen Wallet, die nur du selbst kontrollierst.", "claimBtn": "Beanspruchen", "claimFailed": "Dieses Geschenk wurde bereits beansprucht oder ist nicht mehr verfügbar.", "claimedTitle": "Beansprucht!", - "claimedBody": "Dein Bitcoin ist unterwegs. Sichere deine Wiederherstellungsphrase, um es zu schützen." -} + "claimedBody": "Dein Bitcoin ist unterwegs. Sichere deine Wiederherstellungsphrase, um es zu schützen.", + "giftRevoke": "Widerrufen", + "giftRevokeConfirm": "Dieses Geschenk widerrufen? Die Münze geht zurück in deine Wallet und der Link funktioniert nicht mehr.", + "giftRevoked": "Geschenk widerrufen" +}
\ No newline at end of file diff --git a/src/locales/es.json b/src/locales/es.json index e1f1d43..5d4c3b2 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -160,10 +160,12 @@ "giftAmountInvalid": "Introduce un importe válido.", "giftAnother": "Crear otro", "giftReserved": "{n} de monedas reservadas para regalos sin reclamar", - "giftReclaim": "Recuperar", "claimBody": "Reclámalo en una billetera totalmente nueva que solo tú controlas.", "claimBtn": "Reclamarlo", "claimFailed": "Este regalo ya ha sido reclamado o ya no está disponible.", "claimedTitle": "¡Reclamado!", - "claimedBody": "Tu Bitcoin está en camino. Haz una copia de seguridad de tu frase de recuperación para mantenerlo a salvo." -} + "claimedBody": "Tu Bitcoin está en camino. Haz una copia de seguridad de tu frase de recuperación para mantenerlo a salvo.", + "giftRevoke": "Revocar", + "giftRevokeConfirm": "¿Revocar este regalo? Esto devuelve la moneda a tu monedero y desactiva el enlace.", + "giftRevoked": "Regalo revocado" +}
\ No newline at end of file diff --git a/src/locales/fr.json b/src/locales/fr.json index 8754e3a..1cd7992 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -160,10 +160,12 @@ "giftAmountInvalid": "Saisissez un montant valide.", "giftAnother": "En créer un autre", "giftReserved": "{n} de fonds mis de côté pour des cadeaux non réclamés", - "giftReclaim": "Récupérer", "claimBody": "Récupérez-les dans un tout nouveau portefeuille que vous seul contrôlez.", "claimBtn": "Récupérer", "claimFailed": "Ce cadeau a déjà été réclamé ou n’est plus disponible.", "claimedTitle": "Récupéré !", - "claimedBody": "Vos Bitcoin sont en route. Sauvegardez votre phrase de récupération pour les garder en sécurité." + "claimedBody": "Vos Bitcoin sont en route. Sauvegardez votre phrase de récupération pour les garder en sécurité.", + "giftRevoke": "Révoquer", + "giftRevokeConfirm": "Révoquer ce cadeau ? La pièce revient dans votre portefeuille et le lien cesse de fonctionner.", + "giftRevoked": "Cadeau révoqué" }
\ No newline at end of file diff --git a/src/locales/hi.json b/src/locales/hi.json index b3b439f..10b548c 100644 --- a/src/locales/hi.json +++ b/src/locales/hi.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "एक मान्य राशि दर्ज करें।", "giftAnother": "एक और बनाएँ", "giftReserved": "{n} सिक्का बिना दावे वाले उपहारों के लिए अलग रखा गया", - "giftReclaim": "वापस लें", "claimBody": "इसे एक बिल्कुल नए वॉलेट में प्राप्त करें जिसे केवल आप नियंत्रित करते हैं।", "claimBtn": "इसे प्राप्त करें", "claimFailed": "इस उपहार का दावा पहले ही किया जा चुका है या यह अब उपलब्ध नहीं है।", "claimedTitle": "प्राप्त हो गया!", "claimedBody": "आपका Bitcoin रास्ते में है। इसे सुरक्षित रखने के लिए अपने रिकवरी वाक्यांश का बैकअप लें।", "giftLinkReveal": "उपहार लिंक बनाएँ", - "copyLink": "लिंक कॉपी करें" -} + "copyLink": "लिंक कॉपी करें", + "giftRevoke": "रद्द करें", + "giftRevokeConfirm": "यह उपहार रद्द करें? यह सिक्का आपके वॉलेट में वापस भेज देता है और लिंक काम करना बंद कर देता है।", + "giftRevoked": "उपहार रद्द किया गया" +}
\ No newline at end of file diff --git a/src/locales/id.json b/src/locales/id.json index 7255730..924cdd5 100644 --- a/src/locales/id.json +++ b/src/locales/id.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "Masukkan jumlah yang valid.", "giftAnother": "Buat lagi", "giftReserved": "{n} koin disisihkan untuk hadiah yang belum diklaim", - "giftReclaim": "Ambil kembali", "claimBody": "Klaim ke dompet baru yang hanya Anda kendalikan.", "claimBtn": "Klaim", "claimFailed": "Hadiah ini sudah diklaim atau tidak lagi tersedia.", "claimedTitle": "Diklaim!", "claimedBody": "Bitcoin Anda sedang dalam perjalanan. Cadangkan frasa pemulihan Anda agar tetap aman.", "giftLinkReveal": "Buat tautan hadiah", - "copyLink": "Salin tautan" -} + "copyLink": "Salin tautan", + "giftRevoke": "Cabut", + "giftRevokeConfirm": "Cabut hadiah ini? Ini mengembalikan koin ke dompet Anda dan menonaktifkan tautannya.", + "giftRevoked": "Hadiah dicabut" +}
\ No newline at end of file diff --git a/src/locales/ja.json b/src/locales/ja.json index 346f096..739bd4b 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "有効な金額を入力してください。", "giftAnother": "もう一つ作成", "giftReserved": "未受取のギフト用に {n} のコインを確保中", - "giftReclaim": "回収", "claimBody": "あなただけが管理できる真新しいウォレットに受け取りましょう。", "claimBtn": "受け取る", "claimFailed": "このギフトはすでに受け取られたか、現在利用できません。", "claimedTitle": "受け取りました!", "claimedBody": "Bitcoin が間もなく届きます。安全に保つため、復元フレーズをバックアップしてください。", "giftLinkReveal": "ギフトリンクを作成", - "copyLink": "リンクをコピー" -} + "copyLink": "リンクをコピー", + "giftRevoke": "取り消す", + "giftRevokeConfirm": "このギフトを取り消しますか?コインがウォレットに戻り、リンクは無効になります。", + "giftRevoked": "ギフトを取り消しました" +}
\ No newline at end of file diff --git a/src/locales/ko.json b/src/locales/ko.json index 3d0face..265d55c 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "올바른 금액을 입력하세요.", "giftAnother": "또 만들기", "giftReserved": "받지 않은 선물을 위해 따로 둔 코인 {n}개", - "giftReclaim": "되찾기", "claimBody": "자신만 통제하는 완전히 새로운 지갑으로 받으세요.", "claimBtn": "받기", "claimFailed": "이 선물은 이미 수령되었거나 더 이상 이용할 수 없습니다.", "claimedTitle": "수령 완료!", "claimedBody": "Bitcoin이 전송되고 있습니다. 안전하게 보관하려면 복구 문구를 백업하세요.", "giftLinkReveal": "선물 링크 만들기", - "copyLink": "링크 복사" + "copyLink": "링크 복사", + "giftRevoke": "취소", + "giftRevokeConfirm": "이 선물을 취소할까요? 코인이 지갑으로 돌아가고 링크가 작동하지 않게 됩니다.", + "giftRevoked": "선물이 취소됨" }
\ No newline at end of file diff --git a/src/locales/mr.json b/src/locales/mr.json index f5f0e8e..748713e 100644 --- a/src/locales/mr.json +++ b/src/locales/mr.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "वैध रक्कम टाका.", "giftAnother": "आणखी एक तयार करा", "giftReserved": "{n} नाणी न घेतलेल्या भेटींसाठी बाजूला ठेवली", - "giftReclaim": "परत मिळवा", "claimBody": "ते फक्त तुमच्याच नियंत्रणातील एका नव्या कोऱ्या वॉलेटमध्ये घ्या.", "claimBtn": "ते घ्या", "claimFailed": "ही भेट आधीच घेतली गेली आहे किंवा आता उपलब्ध नाही.", "claimedTitle": "घेतले!", "claimedBody": "तुमचे Bitcoin येत आहे. ते सुरक्षित ठेवण्यासाठी तुमच्या रिकव्हरी वाक्यांशाचा बॅकअप घ्या.", "giftLinkReveal": "भेट लिंक तयार करा", - "copyLink": "लिंक कॉपी करा" -} + "copyLink": "लिंक कॉपी करा", + "giftRevoke": "रद्द करा", + "giftRevokeConfirm": "ही भेट रद्द करायची? हे नाणे तुमच्या वॉलेटमध्ये परत पाठवते आणि लिंक काम करणे थांबवते.", + "giftRevoked": "भेट रद्द केली" +}
\ No newline at end of file diff --git a/src/locales/pt.json b/src/locales/pt.json index b0b1093..db2d2f2 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -160,10 +160,12 @@ "giftAmountInvalid": "Digite um valor válido.", "giftAnother": "Criar outro", "giftReserved": "{n} de moeda reservada para presentes não resgatados", - "giftReclaim": "Recuperar", "claimBody": "Resgate para uma carteira novinha que só você controla.", "claimBtn": "Resgatar", "claimFailed": "Este presente já foi resgatado ou não está mais disponível.", "claimedTitle": "Resgatado!", - "claimedBody": "Seus Bitcoin estão a caminho. Faça backup da sua frase de recuperação para mantê-los seguros." + "claimedBody": "Seus Bitcoin estão a caminho. Faça backup da sua frase de recuperação para mantê-los seguros.", + "giftRevoke": "Revogar", + "giftRevokeConfirm": "Revogar este presente? Isso devolve a moeda à sua carteira e o link para de funcionar.", + "giftRevoked": "Presente revogado" }
\ No newline at end of file diff --git a/src/locales/ru.json b/src/locales/ru.json index 5ef7967..8673803 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "Введите корректную сумму.", "giftAnother": "Создать ещё один", "giftReserved": "{n} монет отложено для невостребованных подарков", - "giftReclaim": "Вернуть", "claimBody": "Получите его в совершенно новый кошелёк, которым управляете только вы.", "claimBtn": "Получить", "claimFailed": "Этот подарок уже получен или больше недоступен.", "claimedTitle": "Получено!", "claimedBody": "Ваш Bitcoin уже в пути. Сделайте резервную копию фразы восстановления, чтобы сохранить его в безопасности.", "giftLinkReveal": "Создать ссылку-подарок", - "copyLink": "Копировать ссылку" -} + "copyLink": "Копировать ссылку", + "giftRevoke": "Отозвать", + "giftRevokeConfirm": "Отозвать этот подарок? Монета вернётся в ваш кошелёк, а ссылка перестанет работать.", + "giftRevoked": "Подарок отозван" +}
\ No newline at end of file diff --git a/src/locales/sw.json b/src/locales/sw.json index 1f5c9e5..5a53296 100644 --- a/src/locales/sw.json +++ b/src/locales/sw.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "Ingiza kiasi sahihi.", "giftAnother": "Tengeneza nyingine", "giftReserved": "{n} sarafu imewekwa kando kwa zawadi ambazo hazijadaiwa", - "giftReclaim": "Dai tena", "claimBody": "Idai kwenye pochi mpya kabisa unayoidhibiti wewe pekee.", "claimBtn": "Idai", "claimFailed": "Zawadi hii tayari imedaiwa au haipatikani tena.", "claimedTitle": "Imedaiwa!", "claimedBody": "Bitcoin yako inakuja. Hifadhi kifungu chako cha kurejesha ili kuilinda.", "giftLinkReveal": "Tengeneza kiungo cha zawadi", - "copyLink": "Nakili kiungo" -} + "copyLink": "Nakili kiungo", + "giftRevoke": "Batilisha", + "giftRevokeConfirm": "Batilisha zawadi hii? Hii inarudisha sarafu kwenye pochi yako na kiungo kinaacha kufanya kazi.", + "giftRevoked": "Zawadi imebatilishwa" +}
\ No newline at end of file diff --git a/src/locales/ta.json b/src/locales/ta.json index 6fce3fb..464bd9b 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "சரியான தொகையை உள்ளிடவும்.", "giftAnother": "மற்றொன்றை உருவாக்கு", "giftReserved": "உரிமை கொள்ளப்படாத பரிசுகளுக்காக {n} நாணயம் ஒதுக்கப்பட்டுள்ளது", - "giftReclaim": "மீட்டெடு", "claimBody": "நீங்கள் மட்டுமே கட்டுப்படுத்தும் புத்தம்புதிய வாலட்டிற்குள் இதை உரிமை கொள்ளுங்கள்.", "claimBtn": "உரிமை கொள்", "claimFailed": "இந்தப் பரிசு ஏற்கனவே உரிமை கொள்ளப்பட்டுவிட்டது அல்லது இனி கிடைக்கவில்லை.", "claimedTitle": "உரிமை கொள்ளப்பட்டது!", "claimedBody": "உங்கள் Bitcoin வந்துகொண்டிருக்கிறது. அதைப் பாதுகாப்பாக வைக்க உங்கள் மீட்பு சொற்றொடரைக் காப்புப்பிரதி எடுங்கள்.", "giftLinkReveal": "பரிசு இணைப்பை உருவாக்கு", - "copyLink": "இணைப்பை நகலெடு" + "copyLink": "இணைப்பை நகலெடு", + "giftRevoke": "திரும்பப் பெறு", + "giftRevokeConfirm": "இந்த பரிசை திரும்பப் பெறவா? இது நாணயத்தை உங்கள் வாலெட்டுக்குத் திருப்பி, இணைப்பு செயல்படுவதை நிறுத்தும்.", + "giftRevoked": "பரிசு திரும்பப் பெறப்பட்டது" }
\ No newline at end of file diff --git a/src/locales/te.json b/src/locales/te.json index 06dcd72..81bfa9a 100644 --- a/src/locales/te.json +++ b/src/locales/te.json @@ -158,10 +158,12 @@ "giftAmountInvalid": "సరైన మొత్తాన్ని నమోదు చేయండి.", "giftAnother": "మరొకటి సృష్టించు", "giftReserved": "క్లెయిమ్ చేయని బహుమతుల కోసం {n} నాణేలు పక్కన పెట్టబడ్డాయి", - "giftReclaim": "తిరిగి పొందు", "claimBody": "మీరు మాత్రమే నియంత్రించే సరికొత్త వాలెట్లోకి దాన్ని క్లెయిమ్ చేసుకోండి.", "claimBtn": "క్లెయిమ్ చేసుకోండి", "claimFailed": "ఈ బహుమతి ఇప్పటికే క్లెయిమ్ చేయబడింది లేదా ఇక అందుబాటులో లేదు.", "claimedTitle": "క్లెయిమ్ అయింది!", - "claimedBody": "మీ Bitcoin మీ వద్దకు వస్తోంది. దాన్ని సురక్షితంగా ఉంచడానికి మీ రికవరీ ఫ్రేజ్ను బ్యాకప్ చేయండి." -} + "claimedBody": "మీ Bitcoin మీ వద్దకు వస్తోంది. దాన్ని సురక్షితంగా ఉంచడానికి మీ రికవరీ ఫ్రేజ్ను బ్యాకప్ చేయండి.", + "giftRevoke": "రద్దు చేయి", + "giftRevokeConfirm": "ఈ బహుమతిని రద్దు చేయాలా? ఇది నాణేన్ని మీ వాలెట్కు తిరిగి పంపి, లింక్ పనిచేయడం ఆపేస్తుంది.", + "giftRevoked": "బహుమతి రద్దు చేయబడింది" +}
\ No newline at end of file diff --git a/src/locales/tr.json b/src/locales/tr.json index 39eab0f..8956c9c 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "Geçerli bir tutar girin.", "giftAnother": "Bir tane daha oluştur", "giftReserved": "Talep edilmemiş hediyeler için {n} coin ayrıldı", - "giftReclaim": "Geri al", "claimBody": "Yalnızca kendi kontrolünüzdeki yepyeni bir cüzdana alın.", "claimBtn": "Talep et", "claimFailed": "Bu hediye zaten talep edilmiş veya artık kullanılamıyor.", "claimedTitle": "Talep edildi!", "claimedBody": "Bitcoin’iniz yolda. Güvende tutmak için kurtarma ifadenizi yedekleyin.", "giftLinkReveal": "Hediye bağlantısı oluştur", - "copyLink": "Bağlantıyı kopyala" + "copyLink": "Bağlantıyı kopyala", + "giftRevoke": "İptal et", + "giftRevokeConfirm": "Bu hediye iptal edilsin mi? Bu, parayı cüzdanınıza geri gönderir ve bağlantıyı devre dışı bırakır.", + "giftRevoked": "Hediye iptal edildi" }
\ No newline at end of file diff --git a/src/locales/ur.json b/src/locales/ur.json index 417f9f8..8bbf3e5 100644 --- a/src/locales/ur.json +++ b/src/locales/ur.json @@ -160,10 +160,12 @@ "giftAmountInvalid": "درست رقم درج کریں۔", "giftAnother": "ایک اور بنائیں", "giftReserved": "{n} سکے غیر وصول شدہ تحائف کے لیے الگ رکھے گئے", - "giftReclaim": "واپس لیں", "claimBody": "اسے ایک بالکل نئے والیٹ میں وصول کریں جو صرف آپ کے کنٹرول میں ہو۔", "claimBtn": "وصول کریں", "claimFailed": "اس تحفے کا پہلے ہی دعویٰ کیا جا چکا ہے یا یہ اب دستیاب نہیں۔", "claimedTitle": "وصول ہو گیا!", - "claimedBody": "آپ کا Bitcoin راستے میں ہے۔ اسے محفوظ رکھنے کے لیے اپنے بحالی فقرے کا بیک اپ بنا لیں۔" -} + "claimedBody": "آپ کا Bitcoin راستے میں ہے۔ اسے محفوظ رکھنے کے لیے اپنے بحالی فقرے کا بیک اپ بنا لیں۔", + "giftRevoke": "منسوخ کریں", + "giftRevokeConfirm": "یہ تحفہ منسوخ کریں؟ یہ سکہ آپ کے والیٹ میں واپس بھیج دیتا ہے اور لنک کام کرنا بند کر دیتا ہے۔", + "giftRevoked": "تحفہ منسوخ ہو گیا" +}
\ No newline at end of file diff --git a/src/locales/vi.json b/src/locales/vi.json index 2c7786f..4de3cd0 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "Nhập một số tiền hợp lệ.", "giftAnother": "Tạo cái khác", "giftReserved": "{n} coin được để dành cho các món quà chưa nhận", - "giftReclaim": "Lấy lại", "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.", "claimBtn": "Nhận ngay", "claimFailed": "Món quà này đã được nhận hoặc không còn khả dụng.", "claimedTitle": "Đã nhận!", "claimedBody": "Bitcoin của bạn đang trên đường tới. Hãy sao lưu cụm từ khôi phục để giữ an toàn.", "giftLinkReveal": "Tạo liên kết tặng", - "copyLink": "Sao chép liên kết" -} + "copyLink": "Sao chép liên kết", + "giftRevoke": "Thu hồi", + "giftRevokeConfirm": "Thu hồi quà này? Việc này chuyển đồng coin về ví của bạn và khiến liên kết ngừng hoạt động.", + "giftRevoked": "Đã thu hồi quà" +}
\ No newline at end of file diff --git a/src/locales/zh.json b/src/locales/zh.json index 6de1544..2e990ba 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -158,12 +158,14 @@ "giftAmountInvalid": "请输入有效金额。", "giftAnother": "再创建一个", "giftReserved": "{n} 枚币已预留给未领取的礼物", - "giftReclaim": "收回", "claimBody": "将它领取到一个仅由你自己掌控的全新钱包中。", "claimBtn": "领取", "claimFailed": "此礼物已被领取或不再可用。", "claimedTitle": "已领取!", "claimedBody": "你的 Bitcoin 正在到账。请备份你的恢复助记词以妥善保管。", "giftLinkReveal": "创建赠送链接", - "copyLink": "复制链接" + "copyLink": "复制链接", + "giftRevoke": "撤销", + "giftRevokeConfirm": "撤销此礼物?这会将这笔币退回你的钱包,并使链接失效。", + "giftRevoked": "礼物已撤销" }
\ No newline at end of file diff --git a/src/wallet.js b/src/wallet.js index 06af3dc..b5945ff 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -787,6 +787,17 @@ export class Wallet { this.reservedSet().delete(id); this._saveReserved(); } + + // Truly revoke an unclaimed gift: spend its coin back into our own wallet, + // which double-spends the gift's presigned input so the link can't be claimed + // once this confirms. Uses a high fee to win any race with a claimer. + async revokeGift(id, feeRate) { + const draft = this.buildTx({ recipients: [{ address: this.freshChange().address }], feeRate, coinIds: [id], sendMax: true }); + const hexTx = this.sign(draft.tx); + const txid = await this.broadcast(hexTx); + this.unreserve(id); + return txid; + } // Active gifts whose coin is still unspent (drops claimed/spent ones). activeGifts() { const live = new Set(this.utxos.map((u) => utxoId(u))); |
