Skip to content

Add wallet Sign Message flow for CEX ownership verification#6065

Open
j0ntz wants to merge 3 commits into
developfrom
jon/sign-message-cex
Open

Add wallet Sign Message flow for CEX ownership verification#6065
j0ntz wants to merge 3 commits into
developfrom
jon/sign-message-cex

Conversation

@j0ntz

@j0ntz j0ntz commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Requirements

If you have made any visual changes to the GUI. Make sure you have:

  • Tested on iOS device
  • Tested on Android device
  • Tested on small-screen device (iPod Touch)
  • Tested on large-screen device (tablet)

Description

Adds an in-app Sign Message flow so a user can prove ownership of a self-hosted wallet by signing an exchange-provided message. This addresses EU Travel Rule / TFR withdrawal checks where CEXs/CASPs (Kraken, Coinbase, Bitvavo, Bitpanda, OKX, Bringin, NiceHash, etc.) require a signed message from the destination wallet instead of a manual ID/selfie proof.

BTC-first, per the task scope.

What it does

  • Adds a Sign Message option to the wallet list menu, restricted to Bitcoin-family (UTXO) wallets whose plugin implements message signing.
  • Opens a new SignMessageScene that shows the wallet's receive address (copyable, so the user can hand it to the exchange), a multiline message input, and a Sign Message button.
  • Signs with wallet.signMessage(message, { otherParams: { publicAddress } }) and displays the resulting base64 signature in a copyable card.
  • Includes a short phishing-safety note ("only sign messages from a service you trust; a signature never reveals your private keys").

Implementation notes

  • signMessage is used rather than signBytes because for Bitcoin signBytes base64-re-encodes the bytes before signing, which would produce a signature over the wrong data. signMessage signs the literal UTF-8 message the exchange verifies (same pattern already used by bityProvider and EdgeProviderServer).
  • The signing address is one the wallet owns (from wallet.getAddresses), because the UTXO plugin requires the address to be in its data layer.

Files

  • SignMessageScene.tsx (new scene)
  • routerTypes.tsx, Main.tsx (route + scene registration)
  • WalletListMenuActions.tsx, WalletListMenuModal.tsx (menu entry, UTXO-scoped)
  • en_US.ts (strings)

Asana: https://app.asana.com/0/1215088146871429/1209296431612665

Testing

Verified end-to-end on the iOS simulator (edge-funds, My Bitcoin wallet): opened the wallet menu, tapped Sign Message, entered a message, and confirmed a valid base64 signature was produced and displayed. Proof screenshots attached below.


Note

Medium Risk
Signing invokes wallet private-key operations and users may sign untrusted messages, though keys are not exposed and address ownership is validated by the plugin.

Overview
Adds a Sign Message entry to the wallet list menu for Bitcoin-family (UTXO) wallets, so users can prove self-custody when a CEX asks for a signed withdrawal message (e.g. Travel Rule checks).

Choosing it opens a new signMessage screen: an editable signing address (prefilled from the wallet’s receive address, with Use default address), a multiline field for the exchange’s exact message, and a copyable signature after wallet.signMessage runs with that address. Inputs lock while signing; changing address or message clears a stale signature. Copy includes a short trust/safety note and clearer errors when the wallet does not own the address.

Navigation, menu actions, router types, and English strings are wired to match existing wallet-menu patterns.

Reviewed by Cursor Bugbot for commit 2a248af. Bugbot is set up for automated code reviews on this repo. Configure here.

@j0ntz

j0ntz commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

📸 Test evidence (iOS sim)

agent proof 1209296431612665 01 wallet menu sign message

agent proof 1209296431612665 01 wallet menu sign message

agent proof 1209296431612665 02 sign message scene

agent proof 1209296431612665 02 sign message scene

agent proof 1209296431612665 03 signature success

agent proof 1209296431612665 03 signature success

Captured by the agent's in-app test run (build-and-test).

Comment thread src/components/scenes/SignMessageScene.tsx
Comment thread src/components/scenes/SignMessageScene.tsx
Comment thread src/locales/en_US.ts Outdated
@j0ntz j0ntz force-pushed the jon/sign-message-cex branch from 97138ed to 7624da7 Compare July 1, 2026 22:18
@j0ntz

j0ntz commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

📸 Test evidence (after bugbot fixes)

agent proof 1209296431612665 04 segwit signature success

agent proof 1209296431612665 04 segwit signature success

agent proof 1209296431612665 05 signature cleared on edit

agent proof 1209296431612665 05 signature cleared on edit

Captured by the agent's in-app test run (build-and-test).

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7624da7. Configure here.

Comment thread src/components/scenes/SignMessageScene.tsx
j0ntz added 2 commits July 1, 2026 15:22
Adds a Sign Message option to the wallet list menu for Bitcoin-family
(UTXO) wallets. The new scene shows the wallet's receive address, lets
the user paste an exchange-provided message, signs it with the wallet
key, and returns a copyable signature. This lets users prove control of
a self-hosted wallet for CEX/CASP withdrawal checks (EU Travel Rule)
without manual ID/selfie verification.
Add signMessageInput and signMessageButton testIDs to the Sign Message
scene so UI automation can drive the message field and sign action by a
stable selector.
@j0ntz j0ntz force-pushed the jon/sign-message-cex branch from 7624da7 to d59ad8d Compare July 1, 2026 22:23
The Sign Message scene now shows the wallet's receive address in an editable
field instead of a read-only row. Exchanges typically ask a user to prove
control of the specific address they already provided (often a previously-used
one), so the user can replace the default with that address. The wallet must
control whichever address is entered; the plugin signs with the key derived
from that address's stored derivation path and rejects any address it does not
own, surfaced as a clear error. Editing the address clears any prior signature,
and a Use default address link restores the auto-detected receive address.
@j0ntz

j0ntz commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

📸 Test evidence (followup: user-selectable signing address, Ravencoin UTXO wallet on iOS sim)

agent proof 1209296431612665 01 signmsg default address

agent proof 1209296431612665 01 signmsg default address

agent proof 1209296431612665 02 signature default address

agent proof 1209296431612665 02 signature default address

agent proof 1209296431612665 03 address edited signature cleared

agent proof 1209296431612665 03 address edited signature cleared

agent proof 1209296431612665 04 signature after reset

agent proof 1209296431612665 04 signature after reset

Captured by the agent's in-app test run (build-and-test).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant