From 17c66dcc0bb42ddd69701a616567228f8d94e1ab Mon Sep 17 00:00:00 2001 From: Jeremy <261848901+jeremy-consensys@users.noreply.github.com> Date: Wed, 6 May 2026 17:22:22 +0800 Subject: [PATCH 1/3] fix: warn on self-sends in sendTransfer confirmation The dApp-initiated sendTransfer flow built ConfirmSendFormContext without checking whether the recipient address belonged to the sending account, so UnifiedSendFormView rendered self-sends as ordinary outgoing transfers. The signPsbt flow already runs account.isMine on each output. Bring sendTransfer to parity: derive isMine from the recipient's script_pubkey in JSXConfirmationRepository and surface a warning banner in the confirmation modal when it's true. --- packages/snap/locales/en.json | 8 +++- packages/snap/messages.json | 6 +++ packages/snap/snap.manifest.json | 2 +- packages/snap/src/entities/send-flow.ts | 1 + .../unified-send-flow/UnifiedSendFormView.tsx | 13 ++++++ .../store/JSXConfirmationRepository.test.tsx | 46 +++++++++++++++++++ .../src/store/JSXConfirmationRepository.tsx | 12 +++++ 7 files changed, 86 insertions(+), 2 deletions(-) diff --git a/packages/snap/locales/en.json b/packages/snap/locales/en.json index 0542ef896..1a15f4cec 100644 --- a/packages/snap/locales/en.json +++ b/packages/snap/locales/en.json @@ -211,6 +211,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Transaction request" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The funds will stay in your account." + }, "confirmation.requestOrigin": { "message": "Request from" }, @@ -257,4 +263,4 @@ "message": "No" } } -} +} \ No newline at end of file diff --git a/packages/snap/messages.json b/packages/snap/messages.json index 1af59a2c1..c5073dbec 100644 --- a/packages/snap/messages.json +++ b/packages/snap/messages.json @@ -209,6 +209,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Transaction request" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The funds will stay in your account." + }, "confirmation.requestOrigin": { "message": "Request from" }, diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 0d576bac5..eb27590f5 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/snap-bitcoin-wallet.git" }, "source": { - "shasum": "1jbPT93y4v8JjV5Sj8zdfhhk9Eq1GJrTjSjciRYsl4c=", + "shasum": "brY11ouz4B0rvJfVVtPYkLGxWqfp4i9eAde0MABrk74=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snap/src/entities/send-flow.ts b/packages/snap/src/entities/send-flow.ts index f47f28dfa..73bd32a25 100644 --- a/packages/snap/src/entities/send-flow.ts +++ b/packages/snap/src/entities/send-flow.ts @@ -18,6 +18,7 @@ export type ConfirmSendFormContext = { locale: string; psbt: string; origin?: string; + isMine?: boolean; }; export type SendFormContext = { diff --git a/packages/snap/src/infra/jsx/unified-send-flow/UnifiedSendFormView.tsx b/packages/snap/src/infra/jsx/unified-send-flow/UnifiedSendFormView.tsx index b283b7715..774cd1451 100644 --- a/packages/snap/src/infra/jsx/unified-send-flow/UnifiedSendFormView.tsx +++ b/packages/snap/src/infra/jsx/unified-send-flow/UnifiedSendFormView.tsx @@ -2,6 +2,7 @@ import { Psbt } from '@metamask/bitcoindevkit'; import type { SnapComponent } from '@metamask/snaps-sdk/jsx'; import { Address, + Banner, Heading, Link, Section, @@ -43,6 +44,7 @@ export const UnifiedSendFormView: SnapComponent = ({ recipient, explorerUrl, origin, + isMine, } = context; const psbt = Psbt.from_string(context.psbt); @@ -60,6 +62,17 @@ export const UnifiedSendFormView: SnapComponent = ({ {null} + {isMine ? ( + + + {t('confirmation.signAndSendTransaction.selfSend.description')} + + + ) : null} +
diff --git a/packages/snap/src/store/JSXConfirmationRepository.test.tsx b/packages/snap/src/store/JSXConfirmationRepository.test.tsx index 37b61f4e1..0498115c1 100644 --- a/packages/snap/src/store/JSXConfirmationRepository.test.tsx +++ b/packages/snap/src/store/JSXConfirmationRepository.test.tsx @@ -28,6 +28,7 @@ import { UnifiedSendFormView } from '../infra/jsx/unified-send-flow'; jest.mock('@metamask/bitcoindevkit', () => ({ Address: { from_script: jest.fn(), + from_string: jest.fn(), }, })); @@ -110,10 +111,12 @@ describe('JSXConfirmationRepository', () => { }); describe('insertSendTransfer', () => { + const mockRecipientScript = mock(); const mockAccount = mock({ id: 'account-id', network: 'bitcoin', publicAddress: mock
({ toString: () => 'fromAddress' }), + isMine: () => false, }); const mockPsbt = mock({ toString: () => 'serialized-psbt', @@ -132,6 +135,9 @@ describe('JSXConfirmationRepository', () => { mockRatesClient.spotPrices.mockResolvedValue( mock({ price: 50000 }), ); + MockedBdkAddress.from_string.mockReturnValue( + mock
({ script_pubkey: mockRecipientScript }), + ); }); it('creates and displays a send transfer interface', async () => { @@ -151,6 +157,7 @@ describe('JSXConfirmationRepository', () => { locale: 'en', psbt: 'serialized-psbt', origin, + isMine: false, }; expect(mockSnapClient.getPreferences).toHaveBeenCalled(); @@ -170,6 +177,44 @@ describe('JSXConfirmationRepository', () => { ); }); + it('marks the recipient as isMine when it belongs to the account', async () => { + const selfSendAccount = mock({ + id: 'account-id', + network: 'bitcoin', + publicAddress: mock
({ toString: () => 'fromAddress' }), + isMine: () => true, + }); + + await repo.insertSendTransfer( + selfSendAccount, + mockPsbt, + recipient, + origin, + ); + + expect(MockedBdkAddress.from_string).toHaveBeenCalledWith( + recipient.address, + selfSendAccount.network, + ); + expect(mockSnapClient.createInterface).toHaveBeenCalledWith( + undefined, + expect.objectContaining({ isMine: true }), + ); + }); + + it('defaults isMine to false when the recipient address fails to parse', async () => { + MockedBdkAddress.from_string.mockImplementation(() => { + throw new Error('Invalid address'); + }); + + await repo.insertSendTransfer(mockAccount, mockPsbt, recipient, origin); + + expect(mockSnapClient.createInterface).toHaveBeenCalledWith( + undefined, + expect.objectContaining({ isMine: false }), + ); + }); + it('throws UserActionError if the user cancels', async () => { mockSnapClient.displayConfirmation.mockResolvedValue(false); await expect( @@ -182,6 +227,7 @@ describe('JSXConfirmationRepository', () => { id: 'account-id', network: 'testnet', publicAddress: mock
({ toString: () => 'fromAddress' }), + isMine: () => false, }); await repo.insertSendTransfer( diff --git a/packages/snap/src/store/JSXConfirmationRepository.tsx b/packages/snap/src/store/JSXConfirmationRepository.tsx index dbf86e9c6..58f0b49bb 100644 --- a/packages/snap/src/store/JSXConfirmationRepository.tsx +++ b/packages/snap/src/store/JSXConfirmationRepository.tsx @@ -88,6 +88,17 @@ export class JSXConfirmationRepository implements ConfirmationRepository { const { locale, currency: fiatCurrency } = await this.#snapClient.getPreferences(); + let isMine = false; + try { + const recipientScript = BdkAddress.from_string( + recipient.address, + account.network, + ).script_pubkey; + isMine = account.isMine(recipientScript); + } catch { + isMine = false; + } + const context: ConfirmSendFormContext = { from: account.publicAddress.toString(), explorerUrl: this.#chainClient.getExplorerUrl(account.network), @@ -99,6 +110,7 @@ export class JSXConfirmationRepository implements ConfirmationRepository { locale, psbt: psbt.toString(), origin, + isMine, }; const messages = await this.#translator.load(locale); From d973a4a1d3c1517efac397a1a317a986000002bf Mon Sep 17 00:00:00 2001 From: Jeremy <261848901+jeremy-consensys@users.noreply.github.com> Date: Wed, 6 May 2026 18:09:31 +0800 Subject: [PATCH 2/3] fix: extend self-send warning to in-app send flow and all locales Address codex audit findings on the previous commit: - isMine was optional and only populated by the dApp keyring path; the in-app SendFlowUseCases.confirmSendFlow renders the same UnifiedSendFormView and was missing the warning. Make isMine required on ConfirmSendFormContext and derive it from the recipient script in both producers. - The new self-send copy was only added to en.json, so non-English locales would render the raw {key} placeholder. Add the keys to every locale file with the English text as a placeholder until translations land. - Adjust the warning copy to acknowledge that self-sends still pay network fees. - Regenerate the snap manifest shasum after the source changes. --- packages/snap/locales/de.json | 6 ++++ packages/snap/locales/el.json | 6 ++++ packages/snap/locales/en.json | 4 +-- packages/snap/locales/es.json | 6 ++++ packages/snap/locales/es_419.json | 6 ++++ packages/snap/locales/fr.json | 6 ++++ packages/snap/locales/hi.json | 6 ++++ packages/snap/locales/id.json | 6 ++++ packages/snap/locales/ja.json | 6 ++++ packages/snap/locales/ko.json | 6 ++++ packages/snap/locales/pt.json | 6 ++++ packages/snap/locales/ru.json | 6 ++++ packages/snap/locales/tl.json | 6 ++++ packages/snap/locales/tr.json | 6 ++++ packages/snap/locales/vi.json | 6 ++++ packages/snap/locales/zh_CN.json | 6 ++++ packages/snap/messages.json | 2 +- packages/snap/snap.manifest.json | 2 +- packages/snap/src/entities/send-flow.ts | 2 +- .../src/use-cases/SendFlowUseCases.test.ts | 31 +++++++++++++++++++ .../snap/src/use-cases/SendFlowUseCases.ts | 12 +++++++ 21 files changed, 138 insertions(+), 5 deletions(-) diff --git a/packages/snap/locales/de.json b/packages/snap/locales/de.json index 127d28bae..dddeb658b 100644 --- a/packages/snap/locales/de.json +++ b/packages/snap/locales/de.json @@ -208,6 +208,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Transaktionsanfrage" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Anfrage von" } diff --git a/packages/snap/locales/el.json b/packages/snap/locales/el.json index 672318abd..0eff56d16 100644 --- a/packages/snap/locales/el.json +++ b/packages/snap/locales/el.json @@ -208,6 +208,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Αίτημα συναλλαγής" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Ζητήθηκε από" } diff --git a/packages/snap/locales/en.json b/packages/snap/locales/en.json index 1a15f4cec..5c8c69f1a 100644 --- a/packages/snap/locales/en.json +++ b/packages/snap/locales/en.json @@ -215,7 +215,7 @@ "message": "Sending to your own address" }, "confirmation.signAndSendTransaction.selfSend.description": { - "message": "The recipient address belongs to this wallet. The funds will stay in your account." + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." }, "confirmation.requestOrigin": { "message": "Request from" @@ -263,4 +263,4 @@ "message": "No" } } -} \ No newline at end of file +} diff --git a/packages/snap/locales/es.json b/packages/snap/locales/es.json index 0079d88d3..371cda0d2 100644 --- a/packages/snap/locales/es.json +++ b/packages/snap/locales/es.json @@ -208,6 +208,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Solicitud de transacción" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Solicitud de" } diff --git a/packages/snap/locales/es_419.json b/packages/snap/locales/es_419.json index 9b75a07a2..e3c29cbbb 100644 --- a/packages/snap/locales/es_419.json +++ b/packages/snap/locales/es_419.json @@ -208,6 +208,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Solicitud de transacción" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Solicitud de" } diff --git a/packages/snap/locales/fr.json b/packages/snap/locales/fr.json index 21c549a7d..239501950 100644 --- a/packages/snap/locales/fr.json +++ b/packages/snap/locales/fr.json @@ -208,6 +208,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Demande de transaction" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Demande de la part de" } diff --git a/packages/snap/locales/hi.json b/packages/snap/locales/hi.json index dbc3ba3e7..f5ef7c5ab 100644 --- a/packages/snap/locales/hi.json +++ b/packages/snap/locales/hi.json @@ -208,6 +208,12 @@ "confirmation.signAndSendTransaction.title": { "message": "ट्रांसेक्शन रिक्वेस्ट" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "इनसे मिला अनुरोध" } diff --git a/packages/snap/locales/id.json b/packages/snap/locales/id.json index 67997e2b9..4c4b93540 100644 --- a/packages/snap/locales/id.json +++ b/packages/snap/locales/id.json @@ -208,6 +208,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Permintaan transaksi" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Permintaan dari" } diff --git a/packages/snap/locales/ja.json b/packages/snap/locales/ja.json index 1232b8e5f..476db885e 100644 --- a/packages/snap/locales/ja.json +++ b/packages/snap/locales/ja.json @@ -208,6 +208,12 @@ "confirmation.signAndSendTransaction.title": { "message": "トランザクションリクエスト" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "要求元" } diff --git a/packages/snap/locales/ko.json b/packages/snap/locales/ko.json index 6c7fd74ac..3d3305e11 100644 --- a/packages/snap/locales/ko.json +++ b/packages/snap/locales/ko.json @@ -178,6 +178,12 @@ "confirmation.signAndSendTransaction.title": { "message": "트랜잭션 요청" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "요청자:" } diff --git a/packages/snap/locales/pt.json b/packages/snap/locales/pt.json index 6d3191a4d..38609f322 100644 --- a/packages/snap/locales/pt.json +++ b/packages/snap/locales/pt.json @@ -178,6 +178,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Solicitação de transação" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Solicitação de" } diff --git a/packages/snap/locales/ru.json b/packages/snap/locales/ru.json index e5604cebe..e0be0afa0 100644 --- a/packages/snap/locales/ru.json +++ b/packages/snap/locales/ru.json @@ -178,6 +178,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Запрос транзакции" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Запрос от" } diff --git a/packages/snap/locales/tl.json b/packages/snap/locales/tl.json index 4b6b18296..2d671764b 100644 --- a/packages/snap/locales/tl.json +++ b/packages/snap/locales/tl.json @@ -178,6 +178,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Hiling na transaksyon" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Kahilingan mula sa/kay" } diff --git a/packages/snap/locales/tr.json b/packages/snap/locales/tr.json index 280a7a67d..4ec3aab3b 100644 --- a/packages/snap/locales/tr.json +++ b/packages/snap/locales/tr.json @@ -178,6 +178,12 @@ "confirmation.signAndSendTransaction.title": { "message": "İşlem talebi" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Talebi gönderen" } diff --git a/packages/snap/locales/vi.json b/packages/snap/locales/vi.json index ef2f934ae..a2e9a273f 100644 --- a/packages/snap/locales/vi.json +++ b/packages/snap/locales/vi.json @@ -178,6 +178,12 @@ "confirmation.signAndSendTransaction.title": { "message": "Yêu cầu giao dịch" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "Yêu cầu từ" } diff --git a/packages/snap/locales/zh_CN.json b/packages/snap/locales/zh_CN.json index 32d907010..253957bd1 100644 --- a/packages/snap/locales/zh_CN.json +++ b/packages/snap/locales/zh_CN.json @@ -178,6 +178,12 @@ "confirmation.signAndSendTransaction.title": { "message": "交易请求" }, + "confirmation.signAndSendTransaction.selfSend.title": { + "message": "Sending to your own address" + }, + "confirmation.signAndSendTransaction.selfSend.description": { + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." + }, "confirmation.requestOrigin": { "message": "请求来自" } diff --git a/packages/snap/messages.json b/packages/snap/messages.json index c5073dbec..5ae58ba5c 100644 --- a/packages/snap/messages.json +++ b/packages/snap/messages.json @@ -213,7 +213,7 @@ "message": "Sending to your own address" }, "confirmation.signAndSendTransaction.selfSend.description": { - "message": "The recipient address belongs to this wallet. The funds will stay in your account." + "message": "The recipient address belongs to this wallet. The amount will stay in your account, but network fees still apply." }, "confirmation.requestOrigin": { "message": "Request from" diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index eb27590f5..44975cebc 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/snap-bitcoin-wallet.git" }, "source": { - "shasum": "brY11ouz4B0rvJfVVtPYkLGxWqfp4i9eAde0MABrk74=", + "shasum": "wwbWFYmkXL1VZpor9Zro1GhiTm5C3X4yb/K8DZHr38U=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snap/src/entities/send-flow.ts b/packages/snap/src/entities/send-flow.ts index 73bd32a25..fcccf17eb 100644 --- a/packages/snap/src/entities/send-flow.ts +++ b/packages/snap/src/entities/send-flow.ts @@ -18,7 +18,7 @@ export type ConfirmSendFormContext = { locale: string; psbt: string; origin?: string; - isMine?: boolean; + isMine: boolean; }; export type SendFormContext = { diff --git a/packages/snap/src/use-cases/SendFlowUseCases.test.ts b/packages/snap/src/use-cases/SendFlowUseCases.test.ts index bedb81c77..0b2bbf19b 100644 --- a/packages/snap/src/use-cases/SendFlowUseCases.test.ts +++ b/packages/snap/src/use-cases/SendFlowUseCases.test.ts @@ -986,6 +986,37 @@ describe('SendFlowUseCases', () => { expect(result).toBe(mockTransaction); }); + it('marks the recipient as isMine when the address belongs to the account', async () => { + const recipientScript = {} as any; + (Address.from_string as jest.Mock).mockReturnValue({ + script_pubkey: recipientScript, + }); + mockAccount.isMine.mockReturnValue(true); + + await useCases.confirmSendFlow(mockAccount, amount, toAddress); + + expect(Address.from_string).toHaveBeenCalledWith( + toAddress, + mockAccount.network, + ); + expect(mockAccount.isMine).toHaveBeenCalledWith(recipientScript); + expect(mockSendFlowRepository.insertConfirmSendForm).toHaveBeenCalledWith( + expect.objectContaining({ isMine: true }), + ); + }); + + it('defaults isMine to false when the recipient address fails to parse', async () => { + (Address.from_string as jest.Mock).mockImplementation(() => { + throw new Error('Invalid address'); + }); + + await useCases.confirmSendFlow(mockAccount, amount, toAddress); + + expect(mockSendFlowRepository.insertConfirmSendForm).toHaveBeenCalledWith( + expect.objectContaining({ isMine: false }), + ); + }); + it('builds a drain transaction when amount equals balance', async () => { const balanceAmount = mock(); balanceAmount.to_sat.mockReturnValue(BigInt(10000)); diff --git a/packages/snap/src/use-cases/SendFlowUseCases.ts b/packages/snap/src/use-cases/SendFlowUseCases.ts index 843c3f30b..4d71f1409 100644 --- a/packages/snap/src/use-cases/SendFlowUseCases.ts +++ b/packages/snap/src/use-cases/SendFlowUseCases.ts @@ -111,6 +111,17 @@ export class SendFlowUseCases { const psbt = templatePsbt.finish(); const currency = networkToCurrencyUnit[account.network]; + let isMine = false; + try { + const recipientScript = Address.from_string( + toAddress, + account.network, + ).script_pubkey; + isMine = account.isMine(recipientScript); + } catch { + isMine = false; + } + // TODO: add all the necessary properties we need here const context: ConfirmSendFormContext = { from: account.publicAddress.toString(), @@ -122,6 +133,7 @@ export class SendFlowUseCases { exchangeRate: await this.#getExchangeRate(account.network, fiatCurrency), network: account.network, locale, + isMine, }; const interfaceId = From b198577104c05e07d383553e98d46e5dfcd3af45 Mon Sep 17 00:00:00 2001 From: Jeremy <261848901+jeremy-consensys@users.noreply.github.com> Date: Thu, 7 May 2026 19:08:04 +0800 Subject: [PATCH 3/3] docs: add changelog entry for self-send confirmation warning Also regenerates snap.manifest.json shasum to match the current bundle output. --- packages/snap/CHANGELOG.md | 1 + packages/snap/snap.manifest.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/snap/CHANGELOG.md b/packages/snap/CHANGELOG.md index bf02a33ae..3a3676bd6 100644 --- a/packages/snap/CHANGELOG.md +++ b/packages/snap/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Show a self-send warning in the send confirmation when the recipient address belongs to the sending account ([#607](https://github.com/MetaMask/snap-bitcoin-wallet/pull/607)) - Show a confirmation dialog before signing a PSBT from KeyringHandler and sending a transfer ([#591](https://github.com/MetaMask/snap-bitcoin-wallet/pull/591)) - Add `resolveAccountAddress` method to KeyringHandler for dApp connectivity ([#590](https://github.com/MetaMask/snap-bitcoin-wallet/pull/590)) diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 44975cebc..36096269a 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/snap-bitcoin-wallet.git" }, "source": { - "shasum": "wwbWFYmkXL1VZpor9Zro1GhiTm5C3X4yb/K8DZHr38U=", + "shasum": "ULNv7Bt/BuxJkLiIo7x79kO0vVLtnZj8CxGoa2bEQ+M=", "location": { "npm": { "filePath": "dist/bundle.js",