11import { div , mul , round } from 'biggystring'
2- import type {
3- EdgeCurrencyConfig ,
4- EdgeSwapQuote ,
5- EdgeSwapRequest ,
6- EdgeSwapToAddressInfo ,
7- EdgeTokenId
8- } from 'edge-core-js'
2+ import type { EdgeTokenId } from 'edge-core-js'
93import * as React from 'react'
104
115import { useHandler } from '../../hooks/useHandler'
@@ -15,7 +9,10 @@ import { useSelector } from '../../types/reactRedux'
159import type { EdgeAppSceneProps , NavigationBase } from '../../types/routerTypes'
1610import { getWalletName } from '../../util/CurrencyWalletHelpers'
1711import {
12+ fetchHoudiniPrivateQuote ,
13+ getPrimaryMultiplier ,
1814 HOUDINI_DESTINATION_ASSETS ,
15+ HOUDINI_DESTINATION_EDGE_ASSETS ,
1916 type HoudiniDestinationAsset ,
2017 isValidHoudiniDestination
2118} from '../../util/houdiniPrivateSend'
@@ -24,7 +21,6 @@ import { EdgeCard } from '../cards/EdgeCard'
2421import { SceneWrapper } from '../common/SceneWrapper'
2522import { SectionHeader } from '../common/SectionHeader'
2623import { ConfirmContinueModal } from '../modals/ConfirmContinueModal'
27- import { RadioListModal } from '../modals/RadioListModal'
2824import { TextInputModal } from '../modals/TextInputModal'
2925import {
3026 WalletListModal ,
@@ -37,26 +33,10 @@ import { EdgeText } from '../themed/EdgeText'
3733interface Props extends EdgeAppSceneProps < 'houdiniPrivateSend' > { }
3834
3935/**
40- * The primary-unit multiplier for an asset, used to convert a user-entered
41- * display amount to and from a native (atomic) amount.
42- */
43- function getPrimaryMultiplier (
44- currencyConfig : EdgeCurrencyConfig ,
45- tokenId : EdgeTokenId
46- ) : string {
47- const { allTokens, currencyInfo } = currencyConfig
48- const denominations =
49- tokenId == null
50- ? currencyInfo . denominations
51- : allTokens [ tokenId ] ?. denominations ?? currencyInfo . denominations
52- return denominations [ 0 ] . multiplier
53- }
54-
55- /**
56- * A minimal prototype flow for a Houdini private send: pick a funded source
57- * wallet, pick a destination asset from the supported set, paste a destination
58- * address, get a live private quote, then create the exchange order and
59- * broadcast the on-chain deposit through core's swap-to-address path.
36+ * A Houdini private send: pick a funded source wallet, pick a destination asset
37+ * (both via the shared `WalletListModal`), paste a destination address, get a
38+ * live private quote, then create the exchange order and broadcast the on-chain
39+ * deposit through core's swap-to-address path.
6040 */
6141export const HoudiniPrivateSendScene : React . FC < Props > = props => {
6242 const { navigation } = props
@@ -103,25 +83,24 @@ export const HoudiniPrivateSendScene: React.FC<Props> = props => {
10383 } )
10484
10585 const handlePickDestAsset = useHandler ( async ( ) => {
106- const selected = await Airship . show < string | undefined > ( bridge => (
107- < RadioListModal
86+ // Reuse the shared wallet picker, filtered to the chains Houdini can
87+ // privately route to, so the destination chain is chosen with the same
88+ // control as the source rather than a bespoke picker.
89+ const result = await Airship . show < WalletListResult > ( bridge => (
90+ < WalletListModal
10891 bridge = { bridge }
109- title = { lstrings . houdini_ps_select_dest_asset }
110- items = { HOUDINI_DESTINATION_ASSETS . map ( asset => ( {
111- icon : '' ,
112- name : `${ asset . displayName } (${ asset . currencyCode } )`
113- } ) ) }
114- selected = {
115- destAsset == null
116- ? undefined
117- : `${ destAsset . displayName } (${ destAsset . currencyCode } )`
118- }
92+ // eslint-disable-next-line @typescript-eslint/no-deprecated
93+ navigation = { navigation as NavigationBase }
94+ headerTitle = { lstrings . houdini_ps_select_dest_asset }
95+ allowedAssets = { HOUDINI_DESTINATION_EDGE_ASSETS }
96+ showCreateWallet
11997 />
12098 ) )
121- if ( selected == null ) return
99+ if ( result ?. type !== 'wallet' ) return
100+ const selectedWallet = currencyWallets [ result . walletId ]
101+ if ( selectedWallet == null ) return
122102 const asset = HOUDINI_DESTINATION_ASSETS . find (
123- candidate =>
124- `${ candidate . displayName } (${ candidate . currencyCode } )` === selected
103+ candidate => candidate . pluginId === selectedWallet . currencyInfo . pluginId
125104 )
126105 if ( asset != null ) {
127106 setDestAsset ( asset )
@@ -196,40 +175,14 @@ export const HoudiniPrivateSendScene: React.FC<Props> = props => {
196175 )
197176 const nativeAmount = round ( mul ( displayAmount , fromMultiplier ) , 0 )
198177
199- const toAddressInfo : EdgeSwapToAddressInfo = {
200- toPluginId : destAsset . pluginId ,
201- toAddress
202- }
203- const request : EdgeSwapRequest = {
178+ const quote = await fetchHoudiniPrivateQuote ( account , {
204179 fromWallet,
205180 fromTokenId,
181+ toPluginId : destAsset . pluginId ,
206182 toTokenId : destAsset . tokenId ,
207- toAddressInfo,
208- nativeAmount,
209- quoteFor : 'from'
210- }
211-
212- // Restrict the prototype to Houdini: a swap-to-address request would
213- // otherwise fan out to every central provider, creating junk orders and
214- // burning their quotas.
215- const disabled : Record < string , true > = { }
216- for ( const pluginId of Object . keys ( account . swapConfig ) ) {
217- if ( pluginId !== 'houdini' ) disabled [ pluginId ] = true
218- }
219-
220- const quotes = await account . fetchSwapQuotes ( request , {
221- preferPluginId : 'houdini' ,
222- disabled
183+ toAddress,
184+ nativeAmount
223185 } )
224- // Houdini-only by design: never fall back to another provider's quote, or
225- // the swap-to-address deposit could be routed through the wrong plugin.
226- const quote : EdgeSwapQuote | undefined = quotes . find (
227- candidate => candidate . pluginId === 'houdini'
228- )
229- if ( quote == null ) {
230- showError ( lstrings . houdini_ps_no_quote )
231- return
232- }
233186
234187 const toConfig = account . currencyConfig [ destAsset . pluginId ]
235188 const toMultiplier = getPrimaryMultiplier ( toConfig , destAsset . tokenId )
0 commit comments