Skip to content

gui: Houdini private send prototype (swap-to-address)#6031

Draft
j0ntz wants to merge 2 commits into
developfrom
jon/houdini-private-send-ui
Draft

gui: Houdini private send prototype (swap-to-address)#6031
j0ntz wants to merge 2 commits into
developfrom
jon/houdini-private-send-ui

Conversation

@j0ntz

@j0ntz j0ntz commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

This branch consumes APIs that are not published yet, so CI will fail until both deps publish and the version pins here are bumped. Opened as a draft for that reason.

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

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

A minimal, dev-only prototype of a Houdini private send: a swap-to-address flow reachable from the Developer test scene.

What it does:

  • New HoudiniPrivateSendScene, reachable from Dev Tab > "Houdini Private Send".
  • Source wallet/asset picked from the user's wallets via the existing WalletListModal.
  • Destination asset picked from a small supported set derived from the Houdini coverage matrix (src/util/houdiniPrivateSend.ts). A production flow would source this dynamically from Houdini's GET /chains.
  • Destination address entered via the existing TextInputModal, validated with the per-chain address regex from the matrix. No new address component.
  • Builds an EdgeSwapRequest with toAddressInfo (no destination wallet), gets a live Houdini private quote, creates the private exchange order, and broadcasts the on-chain deposit through core's swap-to-address path, then lands on the existing swapSuccess scene.
  • Registers the houdini swap plugin and its initOptions, and restricts the prototype request to the houdini plugin so a swap-to-address quote does not fan out to other providers.

The second commit adapts the existing wallet-to-wallet swap scenes to the now-optional toWallet / payoutWalletId introduced by the core change.

Verified in-app on the iOS simulator: a real ETH to BTC private send executed end to end (live private quote, private exchange order created, ETH deposit broadcast on-chain, success scene). Proof screenshots are attached below.

Follow-ups:

  • Un-draft and bump the edge-core-js / edge-exchange-plugins version pins once both deps publish.
  • Productionize the destination set (dynamic GET /chains), add token destinations, and wire memo / destinationTag for the memo-required chains.

Note

Medium Risk
Touches swap quoting/approval and on-chain deposits with real funds; wallet-to-wallet paths now throw if toWallet is missing, but the new flow is dev-gated and Houdini-only.

Overview
Adds a dev-only Houdini private send prototype: a new HoudiniPrivateSendScene (Dev Test → navigation) where users pick a source wallet, a hard-coded destination chain from houdiniPrivateSend, and a validated paste-in address, then build an EdgeSwapRequest with toAddressInfo (no toWallet), fetch quotes with only the houdini plugin enabled, confirm, and approve() to create the private order and broadcast the deposit before routing to swapSuccess.

Wires Houdini into the app via HOUDINI_INIT / swapPlugins.houdini and adds localized copy plus the houdiniPrivateSend route.

Adapts existing wallet-to-wallet swap and display code to optional toWallet / payoutWalletId from core: explicit null checks (or throws) in swap create/confirm/processing, quote UI, and SwapProviderRow; safer category labeling when payoutWalletId is missing; empty payoutWalletId for swap-to-address in transaction details.

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

@j0ntz j0ntz marked this pull request as draft June 12, 2026 08:54
@j0ntz

j0ntz commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

📸 Test evidence: real ETH→BTC Houdini private send on iOS sim

agent proof 1215648766077587 01 houdini scene

agent proof 1215648766077587 01 houdini scene

agent proof 1215648766077587 02 source picker

agent proof 1215648766077587 02 source picker

agent proof 1215648766077587 03 configured

agent proof 1215648766077587 03 configured

agent proof 1215648766077587 04 private quote confirm

agent proof 1215648766077587 04 private quote confirm

agent proof 1215648766077587 05 swap success

agent proof 1215648766077587 05 swap success

agent proof 1215648766077587 06 onchain tx

agent proof 1215648766077587 06 onchain tx

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

Comment thread src/components/scenes/SwapProcessingScene.tsx Fixed
Comment thread src/components/scenes/SwapProcessingScene.tsx Fixed

@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 3 potential issues.

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 731069c. Configure here.

Comment thread src/components/scenes/HoudiniPrivateSendScene.tsx Outdated
Comment thread src/components/scenes/TransactionDetailsScene.tsx
Comment thread src/components/scenes/HoudiniPrivateSendScene.tsx
@j0ntz

j0ntz commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Comments from Paul: "1. log privacy, blockchain privacy, address type needs to be factored in
2. Regarding memos/tags being a large lift according to the initial design proposal - maybe just a 'getMemo' supplied only by Houdini's synthetic wallet would make it possible.
3. toAddressInfo - other than the actual address, duplicate info there that is already in the swap request object."

@j0ntz j0ntz force-pushed the jon/houdini-private-send-ui branch from 731069c to d56d281 Compare June 16, 2026 18:05
Comment thread src/components/scenes/SwapProcessingScene.tsx Fixed
Comment thread src/components/scenes/SwapProcessingScene.tsx Fixed
j0ntz added 2 commits June 16, 2026 11:09
A dev-only swap-to-address flow reachable from the Developer test scene. Pick
a funded source wallet, pick a destination asset from Houdini's supported set,
paste a destination address (validated with Houdini's per-chain regex), get a
live private quote, then create the private exchange order and broadcast the
on-chain deposit via core's swap-to-address path.

Registers the HoudiniSwap plugin and its initOptions. Restricts the prototype
request to the houdini plugin so a swap-to-address quote does not fan out to
other providers.
The swap-to-address change in edge-core-js makes EdgeSwapRequest.toWallet and
EdgeTxActionSwap.payoutWalletId optional (a private send has no destination
wallet). Narrow toWallet to its always-present value in the wallet-to-wallet
swap scenes, and tolerate a missing payoutWalletId in the transaction-action
mappers, so these consumers compile against the new core.
@j0ntz j0ntz force-pushed the jon/houdini-private-send-ui branch from d56d281 to b89674f Compare June 16, 2026 18:09
@j0ntz

j0ntz commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Re Paul's 3 review points:

3. toAddressInfo dedup (done). EdgeSwapToAddressInfo no longer carries toTokenId, which duplicated the request's own toTokenId. The descriptor now carries only toPluginId and toAddress. Core's resolveSwapRequest reads the destination token from request.toTokenId and the redundant toAddressInfo.toTokenId === request.toTokenId match-check is gone. Changes: edge-core-js#724 (type + swap-api.ts + synthetic-wallet.test.ts) and this PR (HoudiniPrivateSendScene.tsx drops toTokenId from the literal). The synthetic destination wallet is built identically, so this is a behavior-preserving refactor.

1. Log / blockchain privacy and address type (plan, needs design alignment).

  • Log privacy: core already redacts toAddressInfo.toAddress to [redacted] in swap-api request logging; the remaining work is to confirm nothing else logs the descriptor's identifying fields end to end (GUI plus plugin), and to extend redaction to any new descriptor field.
  • Blockchain privacy: the swap-to-address path should inherit the same per-chain privacy controls as a normal send. Because the synthetic destination wallet is backed by the real currencyConfig, those settings already apply; the open item is verifying the spend that funds the deposit honors source-wallet privacy (coin control / network privacy) rather than bypassing it.
  • Address type: the per-chain addressValidation regex in HOUDINI_DESTINATION_ASSETS already distinguishes formats. Plan is to carry the resolved address type alongside the address so the confirm screen and the deposit can show / branch on it. Open design question is whether address type lives on the descriptor or is derived from the matched HoudiniDestinationAsset. Deferring implementation until that is settled.

2. getMemo via Houdini's synthetic wallet (plan). Agreed the full memo/tag design is a large lift. The lighter path: Houdini's synthetic destination wallet exposes a getMemo() that returns the memo/tag the deposit requires (Houdini supplies it). The swap flow reads it off the destination wallet at approve time and attaches it to the funding spend, scoped to Houdini only, keeping memo handling out of the generic swap request. Open item is confirming the synthetic-wallet interface can carry getMemo and wiring where the spend reads it; tracking as follow-up rather than this round.

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