diff --git a/apps/wallet-mobile/android/app/src/main/AndroidManifest.xml b/apps/wallet-mobile/android/app/src/main/AndroidManifest.xml
index 2737d66c55..4b9dc445eb 100644
--- a/apps/wallet-mobile/android/app/src/main/AndroidManifest.xml
+++ b/apps/wallet-mobile/android/app/src/main/AndroidManifest.xml
@@ -21,15 +21,13 @@
-
+
-
-
-
+
diff --git a/apps/wallet-mobile/index.js b/apps/wallet-mobile/index.js
index 6f7b0b0843..bf8437e34c 100644
--- a/apps/wallet-mobile/index.js
+++ b/apps/wallet-mobile/index.js
@@ -4,11 +4,13 @@ import 'react-native-gesture-handler' // required by react-navigation
import './global'
import './src/i18n/polyfills' // https://formatjs.io/docs/polyfills
import BigNumber from 'bignumber.js'
+import {enableMapSet} from 'immer'
import {AppRegistry} from 'react-native'
import {name} from './app.json'
import {YoroiApp} from './src/YoroiApp'
+enableMapSet()
BigNumber.config({DECIMAL_PLACES: 19, EXPONENTIAL_AT: [-10, 40]})
AppRegistry.registerComponent(name, () => YoroiApp)
diff --git a/apps/wallet-mobile/package.json b/apps/wallet-mobile/package.json
index 92753fb9c5..10bef414ca 100644
--- a/apps/wallet-mobile/package.json
+++ b/apps/wallet-mobile/package.json
@@ -99,7 +99,7 @@
"@emurgo/csl-mobile-bridge": "6.0.0-alpha.4",
"@emurgo/react-native-blockies-svg": "^0.0.2",
"@emurgo/react-native-hid": "^5.15.6",
- "@emurgo/yoroi-lib": "0.15.0",
+ "@emurgo/yoroi-lib": "0.15.1",
"@formatjs/intl-datetimeformat": "^6.7.0",
"@formatjs/intl-getcanonicallocales": "^2.1.0",
"@formatjs/intl-locale": "^3.2.1",
@@ -125,7 +125,7 @@
"@yoroi/api": "1.5.1",
"@yoroi/common": "1.5.1",
"@yoroi/exchange": "2.0.0",
- "@yoroi/links": "1.5.1",
+ "@yoroi/links": "1.5.3",
"@yoroi/resolver": "2.0.4",
"@yoroi/staking": "1.5.1",
"@yoroi/swap": "1.5.2",
diff --git a/apps/wallet-mobile/src/AppNavigator.tsx b/apps/wallet-mobile/src/AppNavigator.tsx
index ed0f138b04..d34c68b5d9 100644
--- a/apps/wallet-mobile/src/AppNavigator.tsx
+++ b/apps/wallet-mobile/src/AppNavigator.tsx
@@ -15,6 +15,7 @@ import {ModalProvider} from './components/Modal/ModalContext'
import {ModalScreen} from './components/Modal/ModalScreen'
import {AgreementChangedNavigator, InitializationNavigator} from './features/Initialization'
import {LegalAgreement, useLegalAgreement} from './features/Initialization/common'
+import {useDeepLinkWatcher} from './features/Links/common/useDeepLinkWatcher'
import {CONFIG, LINKING_CONFIG, LINKING_PREFIXES} from './legacy/config'
import {DeveloperScreen} from './legacy/DeveloperScreen'
import {AppRoutes} from './navigation'
@@ -27,9 +28,11 @@ const Stack = createStackNavigator()
const navRef = React.createRef>()
export const AppNavigator = () => {
+ useDeepLinkWatcher()
const strings = useStrings()
const [routeName, setRouteName] = React.useState()
+ // NOTE: mind some routes are handled by the event listener
const enableDeepLink = routeName === 'history-list'
const linking = {
diff --git a/apps/wallet-mobile/src/IntialLinkManagerProvider.tsx b/apps/wallet-mobile/src/IntialLinkManagerProvider.tsx
deleted file mode 100644
index 7acd78bb23..0000000000
--- a/apps/wallet-mobile/src/IntialLinkManagerProvider.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import * as React from 'react'
-import {Linking} from 'react-native'
-
-const IntialLinkContext = React.createContext<
- {initialUrl: string | null; setInitialUrl: (initialUrl: string | null) => void} | undefined
->(undefined)
-
-export const InitialLinkProvider: React.FC = ({children}) => {
- const [initialUrl, setInitialUrl] = React.useState(null)
-
- // app is open
- React.useEffect(() => {
- const getUrl = ({url}: {url: string | null}) => {
- if (url !== null) setInitialUrl(url)
- }
- Linking.addEventListener('url', getUrl)
- return () => Linking.removeAllListeners('url')
- }, [])
-
- // app is closed
- React.useEffect(() => {
- const getInitialURL = async () => {
- const url = await Linking.getInitialURL()
- if (url !== null) setInitialUrl(url)
- }
-
- getInitialURL()
- }, [])
-
- return {children}
-}
-
-export const useInitialLink = () => React.useContext(IntialLinkContext) || missingProvider()
-
-const missingProvider = () => {
- throw new Error('InitialLinkProvider is missing')
-}
diff --git a/apps/wallet-mobile/src/TxHistory/TxHistoryNavigator.tsx b/apps/wallet-mobile/src/TxHistory/TxHistoryNavigator.tsx
index 9cae0ac17c..db4051dd6c 100644
--- a/apps/wallet-mobile/src/TxHistory/TxHistoryNavigator.tsx
+++ b/apps/wallet-mobile/src/TxHistory/TxHistoryNavigator.tsx
@@ -24,7 +24,6 @@ import {Boundary, Icon, Spacer} from '../components'
import {claimApiMaker} from '../features/Claim/module/api'
import {ClaimProvider} from '../features/Claim/module/ClaimProvider'
import {ShowSuccessScreen} from '../features/Claim/useCases/ShowSuccessScreen'
-import {useNavigateTo} from '../features/Exchange/common/useNavigateTo'
import {CreateExchangeOrderScreen} from '../features/Exchange/useCases/CreateExchangeOrderScreen/CreateExchangeOrderScreen'
import {SelectProviderFromListScreen} from '../features/Exchange/useCases/SelectProviderFromListScreen/SelectProviderFromListScreen'
import {ShowExchangeResultOrderScreen} from '../features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen'
@@ -126,8 +125,6 @@ export const TxHistoryNavigator = () => {
// navigator components
const headerRightHistory = React.useCallback(() => , [])
- const navigateTo = useNavigateTo()
-
// exchange
const exchangeManager = React.useMemo(() => {
const api = exchangeApiMaker({
@@ -254,9 +251,8 @@ export const TxHistoryNavigator = () => {
headerShown: false,
}}
name="exchange-result"
- >
- {() => }
-
+ component={ShowExchangeResultOrderScreen}
+ />
{
const Stack = createStackNavigator()
export const WalletNavigator = () => {
- const {initialUrl} = useInitialLink()
- const {resetToWalletSelection} = useWalletNavigation()
+ const initialRouteName = useInitialRouteName()
+
+ // initialRoute doens't update the state of the navigator, only at first render
+ // https://reactnavigation.org/docs/auth-flow/
+ if (initialRouteName === 'exchange-result') {
+ return (
+
+
+
+ )
+ }
return (
-
- {() => }
-
-
@@ -187,6 +198,13 @@ export const WalletNavigator = () => {
)
}
+const useInitialRouteName = () => {
+ const {action} = useLinks()
+ const routeName: keyof WalletStackRoutes =
+ action?.info.useCase === 'order/show-create-result' ? 'exchange-result' : 'wallet-selection'
+ return routeName
+}
+
const messages = defineMessages({
transactionsButton: {
id: 'components.common.navigation.transactionsButton',
diff --git a/apps/wallet-mobile/src/YoroiApp.tsx b/apps/wallet-mobile/src/YoroiApp.tsx
index cbaae8db6e..e117eca827 100644
--- a/apps/wallet-mobile/src/YoroiApp.tsx
+++ b/apps/wallet-mobile/src/YoroiApp.tsx
@@ -1,4 +1,5 @@
import {AsyncStorageProvider} from '@yoroi/common'
+import {LinksProvider} from '@yoroi/links'
import {ThemeProvider} from '@yoroi/theme'
import React from 'react'
import {LogBox, Platform, StyleSheet, UIManager} from 'react-native'
@@ -14,7 +15,6 @@ import {ErrorBoundary} from './components/ErrorBoundary'
import {CurrencyProvider} from './features/Settings/Currency/CurrencyContext'
import {LanguageProvider} from './i18n'
import {InitApp} from './InitApp'
-import {InitialLinkProvider} from './IntialLinkManagerProvider'
import {CONFIG} from './legacy/config'
import {setLogLevel} from './legacy/logging'
import {makeMetricsManager, MetricsProvider} from './metrics/metricsManager'
@@ -62,9 +62,9 @@ export const YoroiApp = () => {
-
+
-
+
diff --git a/apps/wallet-mobile/src/features/Exchange/common/useNavigateTo.tsx b/apps/wallet-mobile/src/features/Exchange/common/useNavigateTo.tsx
index fea0659455..a8227d7193 100644
--- a/apps/wallet-mobile/src/features/Exchange/common/useNavigateTo.tsx
+++ b/apps/wallet-mobile/src/features/Exchange/common/useNavigateTo.tsx
@@ -35,13 +35,3 @@ export const useNavigateTo = () => {
}),
}).current
}
-
-export type ExchangeInitRoutes = {
- exchange: {
- coin: string
- coinAmount: number
- fiat: number
- fiatAmount: number
- status: string
- }
-}
diff --git a/apps/wallet-mobile/src/features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen.stories.tsx b/apps/wallet-mobile/src/features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen.stories.tsx
index c037568dbb..e3cd5506b5 100644
--- a/apps/wallet-mobile/src/features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen.stories.tsx
+++ b/apps/wallet-mobile/src/features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen.stories.tsx
@@ -1,73 +1,54 @@
-import {NavigationRouteContext, RouteProp} from '@react-navigation/native'
-import {actions} from '@storybook/addon-actions'
import {storiesOf} from '@storybook/react-native'
import {exchangeDefaultState, ExchangeProvider, successManagerMock} from '@yoroi/exchange'
-import {produce} from 'immer'
+import {LinksProvider} from '@yoroi/links'
import React from 'react'
import {ModalProvider} from '../../../../components'
-import {InitialLinkProvider, useInitialLink} from '../../../../IntialLinkManagerProvider'
import {SelectedWalletProvider} from '../../../../SelectedWallet'
import {mocks as walletMocks} from '../../../../yoroi-wallets/mocks'
-import {ExchangeInitRoutes} from '../../common/useNavigateTo'
import {ShowExchangeResultOrderScreen} from './ShowExchangeResultOrderScreen'
-storiesOf('Exchange ShowExchangeResultOrderScreen', module)
- .addDecorator((story) => {story()})
- .add('no params', () => )
- .add('no info', () => actions('onClose')} />)
- .add('with params', () => )
-
-const Init = () => {
- const {setInitialUrl} = useInitialLink()
- const initialState = produce(exchangeDefaultState, (draft) => {
- draft.orderType = 'buy'
- })
-
- React.useEffect(() => {
- setInitialUrl(
- 'yoroi://ramp-on-off/result?&status=success&fiatAmount=10000&coinAmount=5000&coin=ADA&fiat=USD&provider=encryptus',
- )
- }, [setInitialUrl])
+storiesOf('Exchange ShowExchangeResultOrderScreen', module).add('with deep link data', () => )
+const WithDeepLinkData = () => {
return (
-
- actions('onClose')} />
-
+
+
+
+
+
)
}
-
-const WithParams = () => {
- const {setInitialUrl} = useInitialLink()
- const params: RouteProp['params'] = {
- coin: 'ADA',
- coinAmount: 100,
- fiat: 990,
- fiatAmount: 199,
- status: 'success',
- }
- const initialState = produce(exchangeDefaultState, (draft) => {
- draft.orderType = 'buy'
- })
-
- React.useEffect(() => {
- setInitialUrl(
- 'yoroi://ramp-on-off/result?&status=success&fiatAmount=10000&coinAmount=5000&coin=ADA&fiat=USD&provider=encryptus',
- )
- }, [setInitialUrl])
- return (
-
-
-
-
- actions('onClose')} />
-
-
-
-
- )
-}
diff --git a/apps/wallet-mobile/src/features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen.tsx b/apps/wallet-mobile/src/features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen.tsx
index 7b62d7a7f8..162b01e922 100644
--- a/apps/wallet-mobile/src/features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen.tsx
+++ b/apps/wallet-mobile/src/features/Exchange/useCases/ShowExchangeResultOrderScreen/ShowExchangeResultOrderScreen.tsx
@@ -1,3 +1,5 @@
+import {exchangeApiMaker, exchangeManagerMaker, ExchangeProvider} from '@yoroi/exchange'
+import {LinksYoroiExchangeShowCreateResultParams, useLinks} from '@yoroi/links'
import {useTheme} from '@yoroi/theme'
import * as React from 'react'
import {StyleSheet, TouchableOpacity, View} from 'react-native'
@@ -5,7 +7,7 @@ import {SafeAreaView} from 'react-native-safe-area-context'
import {Button, Icon, Spacer, Text, useModal} from '../../../../components'
import {useStatusBar} from '../../../../components/hooks/useStatusBar'
-import {useInitialLink} from '../../../../IntialLinkManagerProvider'
+import {useWalletNavigation} from '../../../../navigation'
import {DescribeAction} from '../../common/DescribeAction/DescribeAction'
import {useStrings} from '../../common/useStrings'
import {BanxaLogo} from '../../illustrations/BanxaLogo'
@@ -13,82 +15,99 @@ import {EncryptusLogo} from '../../illustrations/EncryptusLogo'
import {WalletAssetImage} from '../../illustrations/WalletAssetImage'
import {ContentResult} from './ContentResult/ContentResult'
-export const ShowExchangeResultOrderScreen = ({onClose}: {onClose: () => void}) => {
+export const ShowExchangeResultOrderScreen = () => {
const strings = useStrings()
const styles = useStyles()
const {openModal} = useModal()
+ const {resetToWalletSelection} = useWalletNavigation()
+ const {action, actionFinished} = useLinks()
- const {setInitialUrl, initialUrl} = useInitialLink()
+ // exchange
+ const exchangeManager = React.useMemo(() => {
+ const api = exchangeApiMaker({
+ isProduction: action?.info?.params?.isSandbox !== true,
+ partner: 'yoroi',
+ })
+
+ const manager = exchangeManagerMaker({api})
+ return manager
+ }, [action?.info?.params?.isSandbox])
+
+ // NOTE: should never happen, caller should handle it
+ if (action == null || action.info.useCase !== 'order/show-create-result') return null
+ const params: LinksYoroiExchangeShowCreateResultParams = action.info.params
const handleOnClose = () => {
- setInitialUrl(null)
- onClose()
+ actionFinished()
+ resetToWalletSelection()
}
const handleOnShowDetails = () => {
openModal(strings.buySellCrypto, )
}
- const {showOrderDetails, params, Logo, name, showProviderDetails} = sanitizeParams(initialUrl)
+ const {showOrderDetails, Logo, name, showProviderDetails} = sanitizeParams(params)
return (
-
-
-
+
+
+
+
+
+
+
+
+ {strings.congrats}
-
+ {showOrderDetails && (
+ <>
+
+
+
+
+
+ >
+ )}
+
-
- {strings.congrats}
+
{showOrderDetails && (
<>
-
+
+ {`${params?.coinAmount ?? 0} ${params?.coin ?? ''}`}
+
-
-
-
+
+
+
+ {`${params?.fiatAmount ?? 0} ${params?.fiat ?? ''}`}
+
>
)}
-
-
-
- {showOrderDetails && (
- <>
-
- {`${params?.coinAmount ?? 0} ${params?.coin ?? ''}`}
-
-
-
-
-
- {`${params?.fiatAmount ?? 0} ${params?.fiat ?? ''}`}
-
- >
- )}
+ {showProviderDetails && (
+ <>
+
- {showProviderDetails && (
- <>
-
+
+
+
-
-
-
+
-
+ {name}
+
+
+ >
+ )}
+
- {name}
-
-
- >
- )}
-
-
-
-
-
-
+
+
+
+
+
)
}
@@ -102,37 +121,15 @@ const providerName = {
banxa: 'Banxa',
} as const
-const sanitizeParams = (url: string | null) => {
- const urlSearchParams = url !== null ? new URLSearchParams(url) : null
- const params =
- urlSearchParams !== null
- ? {
- coin: urlSearchParams.get('coin'),
- coinAmount: urlSearchParams.get('coinAmount'),
- fiat: urlSearchParams.get('fiat'),
- fiatAmount: urlSearchParams.get('fiatAmount'),
- provider: urlSearchParams.get('provider'),
- status: urlSearchParams.get('status'),
- orderType: urlSearchParams.get('orderType'),
- // NOTE: it passes the params below to get it back
- isProduction: urlSearchParams.get('isProduction'),
- // NOTE: later it should open the used wallet and then display
- walletName: urlSearchParams.get('walletName'), // we avoid id - security reasons
- }
- : null
-
+const sanitizeParams = (params: LinksYoroiExchangeShowCreateResultParams) => {
const showOrderDetails =
- params != null &&
- params.coin != null &&
- params.coinAmount != null &&
- params.fiat != null &&
- params.fiatAmount != null
+ params.coin != null && params.coinAmount != null && params.fiat != null && params.fiatAmount != null
const Logo = providerLogo[params?.provider as keyof typeof providerLogo]
const name = providerName[params?.provider as keyof typeof providerName]
const showProviderDetails = Logo != null && name != null
- return {params, showOrderDetails, Logo, name, showProviderDetails}
+ return {showOrderDetails, Logo, name, showProviderDetails}
}
const useStyles = () => {
diff --git a/apps/wallet-mobile/src/features/Links/common/constants.ts b/apps/wallet-mobile/src/features/Links/common/constants.ts
new file mode 100644
index 0000000000..e3a014324c
--- /dev/null
+++ b/apps/wallet-mobile/src/features/Links/common/constants.ts
@@ -0,0 +1,6 @@
+import {freeze} from 'immer'
+
+export const knownApps: Readonly