diff --git a/apps/wallet-mobile/.storybook/storybook.requires.js b/apps/wallet-mobile/.storybook/storybook.requires.js
index 7046d09d9b..21011eaba6 100644
--- a/apps/wallet-mobile/.storybook/storybook.requires.js
+++ b/apps/wallet-mobile/.storybook/storybook.requires.js
@@ -88,6 +88,7 @@ const getStories = () => {
"./src/components/PairedBalance/PairedBalance.stories.tsx": require("../src/components/PairedBalance/PairedBalance.stories.tsx"),
"./src/components/PressableIcon/PressableIcon.stories.tsx": require("../src/components/PressableIcon/PressableIcon.stories.tsx"),
"./src/components/ShareQRCodeCard/ShareQRCodeCard.stories.tsx": require("../src/components/ShareQRCodeCard/ShareQRCodeCard.stories.tsx"),
+ "./src/components/SimpleTab/SimpleTab.stories.tsx": require("../src/components/SimpleTab/SimpleTab.stories.tsx"),
"./src/components/SomethingWentWrong/SomethingWentWrong.stories.tsx": require("../src/components/SomethingWentWrong/SomethingWentWrong.stories.tsx"),
"./src/components/StepperProgress/StepperProgress.stories.tsx": require("../src/components/StepperProgress/StepperProgress.stories.tsx"),
"./src/components/TextInput/TextInput.stories.tsx": require("../src/components/TextInput/TextInput.stories.tsx"),
@@ -121,7 +122,6 @@ const getStories = () => {
"./src/features/Discover/useCases/SearchDappInBrowser/SearchDappInBrowserScreen.stories.tsx": require("../src/features/Discover/useCases/SearchDappInBrowser/SearchDappInBrowserScreen.stories.tsx"),
"./src/features/Discover/useCases/SelectDappFromList/CountDAppsAvailable/CountDAppsAvailable.stories.tsx": require("../src/features/Discover/useCases/SelectDappFromList/CountDAppsAvailable/CountDAppsAvailable.stories.tsx"),
"./src/features/Discover/useCases/SelectDappFromList/CountDAppsConnected/CountDAppsConnected.stories.tsx": require("../src/features/Discover/useCases/SelectDappFromList/CountDAppsConnected/CountDAppsConnected.stories.tsx"),
- "./src/features/Discover/useCases/SelectDappFromList/DAppExplorerTabItem/DAppExplorerTabItem.stories.tsx": require("../src/features/Discover/useCases/SelectDappFromList/DAppExplorerTabItem/DAppExplorerTabItem.stories.tsx"),
"./src/features/Discover/useCases/SelectDappFromList/DAppListItem/DAppItemSkeleton.stories.tsx": require("../src/features/Discover/useCases/SelectDappFromList/DAppListItem/DAppItemSkeleton.stories.tsx"),
"./src/features/Discover/useCases/SelectDappFromList/DAppListItem/DAppListItem.stories.tsx": require("../src/features/Discover/useCases/SelectDappFromList/DAppListItem/DAppListItem.stories.tsx"),
"./src/features/Discover/useCases/SelectDappFromList/DAppTypes/DAppTypes.stories.tsx": require("../src/features/Discover/useCases/SelectDappFromList/DAppTypes/DAppTypes.stories.tsx"),
@@ -173,7 +173,6 @@ const getStories = () => {
"./src/features/Scan/useCases/ShowCameraPermissionDeniedScreen/OpenDeviceAppSettingsButton.stories.tsx": require("../src/features/Scan/useCases/ShowCameraPermissionDeniedScreen/OpenDeviceAppSettingsButton.stories.tsx"),
"./src/features/Scan/useCases/ShowCameraPermissionDeniedScreen/ShowCameraPermissionDeniedScreen.stories.tsx": require("../src/features/Scan/useCases/ShowCameraPermissionDeniedScreen/ShowCameraPermissionDeniedScreen.stories.tsx"),
"./src/features/Send/common/ButtonGroup/ButtonGroup.stories.tsx": require("../src/features/Send/common/ButtonGroup/ButtonGroup.stories.tsx"),
- "./src/features/Send/useCases/ConfirmTx/ConfirmTxScreen.stories.tsx": require("../src/features/Send/useCases/ConfirmTx/ConfirmTxScreen.stories.tsx"),
"./src/features/Send/useCases/ConfirmTx/FailedTx/FailedTxScreen.stories.tsx": require("../src/features/Send/useCases/ConfirmTx/FailedTx/FailedTxScreen.stories.tsx"),
"./src/features/Send/useCases/ConfirmTx/SubmittedTx/SubmittedTxScreen.stories.tsx": require("../src/features/Send/useCases/ConfirmTx/SubmittedTx/SubmittedTxScreen.stories.tsx"),
"./src/features/Send/useCases/ListAmountsToSend/AddToken/AddToken.stories.tsx": require("../src/features/Send/useCases/ListAmountsToSend/AddToken/AddToken.stories.tsx"),
@@ -195,7 +194,6 @@ const getStories = () => {
"./src/features/Settings/Currency/ChangeCurrencyScreen.stories.tsx": require("../src/features/Settings/Currency/ChangeCurrencyScreen.stories.tsx"),
"./src/features/Settings/EasyConfirmation/EasyConfirmationScreen.stories.tsx": require("../src/features/Settings/EasyConfirmation/EasyConfirmationScreen.stories.tsx"),
"./src/features/Settings/EnableLoginWithOs/EnableLoginWithOsScreen.stories.tsx": require("../src/features/Settings/EnableLoginWithOs/EnableLoginWithOsScreen.stories.tsx"),
- "./src/features/Settings/ManageCollateral/ConfirmTx/ConfirmTxScreen.stories.tsx": require("../src/features/Settings/ManageCollateral/ConfirmTx/ConfirmTxScreen.stories.tsx"),
"./src/features/Settings/ManageCollateral/ConfirmTx/FailedTx/FailedTxScreen.stories.tsx": require("../src/features/Settings/ManageCollateral/ConfirmTx/FailedTx/FailedTxScreen.stories.tsx"),
"./src/features/Settings/ManageCollateral/ConfirmTx/SubmittedTx/SubmittedTxScreen.stories.tsx": require("../src/features/Settings/ManageCollateral/ConfirmTx/SubmittedTx/SubmittedTxScreen.stories.tsx"),
"./src/features/Settings/ManageCollateral/ManageCollateralScreen.stories.tsx": require("../src/features/Settings/ManageCollateral/ManageCollateralScreen.stories.tsx"),
diff --git a/apps/wallet-mobile/src/WalletNavigator.tsx b/apps/wallet-mobile/src/WalletNavigator.tsx
index b67c47d16a..c1d3857a7f 100644
--- a/apps/wallet-mobile/src/WalletNavigator.tsx
+++ b/apps/wallet-mobile/src/WalletNavigator.tsx
@@ -24,6 +24,7 @@ import {useLinksShowActionResult} from './features/Links/common/useLinksShowActi
import {MenuNavigator} from './features/Menu/Menu'
import {PortfolioNavigator} from './features/Portfolio/PortfolioNavigator'
import {CatalystNavigator} from './features/RegisterCatalyst/CatalystNavigator'
+import {ReviewTxNavigator} from './features/ReviewTx/ReviewTxNavigator'
import {SearchProvider} from './features/Search/SearchContext'
import {SettingsScreenNavigator} from './features/Settings'
import {NetworkTag} from './features/Settings/ChangeNetwork/NetworkTag'
@@ -258,6 +259,8 @@ export const WalletNavigator = () => {
+
+
{
divider: color.gray_200,
}
- return {colors, styles}
+ return {colors, styles} as const
}
const messages = defineMessages({
diff --git a/apps/wallet-mobile/src/YoroiApp.tsx b/apps/wallet-mobile/src/YoroiApp.tsx
index fc98586531..655676b9c4 100644
--- a/apps/wallet-mobile/src/YoroiApp.tsx
+++ b/apps/wallet-mobile/src/YoroiApp.tsx
@@ -15,6 +15,7 @@ import {ErrorBoundary} from './components/ErrorBoundary/ErrorBoundary'
import {AuthProvider} from './features/Auth/AuthProvider'
import {BrowserProvider} from './features/Discover/common/BrowserProvider'
import {PortfolioTokenActivityProvider} from './features/Portfolio/common/PortfolioTokenActivityProvider'
+import {ReviewTxProvider} from './features/ReviewTx/common/ReviewTxProvider'
import {CurrencyProvider} from './features/Settings/Currency/CurrencyContext'
import {AutomaticWalletOpenerProvider} from './features/WalletManager/context/AutomaticWalletOpeningProvider'
import {WalletManagerProvider} from './features/WalletManager/context/WalletManagerProvider'
@@ -65,7 +66,9 @@ const Yoroi = () => {
-
+
+
+
diff --git a/apps/wallet-mobile/src/components/Icon/Direction.tsx b/apps/wallet-mobile/src/components/Icon/Direction.tsx
index 3f803c624d..7d1e4f714b 100644
--- a/apps/wallet-mobile/src/components/Icon/Direction.tsx
+++ b/apps/wallet-mobile/src/components/Icon/Direction.tsx
@@ -1,6 +1,6 @@
import {ThemedPalette, useTheme} from '@yoroi/theme'
import React from 'react'
-import {StyleSheet, View} from 'react-native'
+import {StyleSheet, View, ViewStyle} from 'react-native'
import {TransactionDirection, TransactionInfo} from '../../yoroi-wallets/types/other'
import {Received} from '../Icon/Received'
@@ -11,9 +11,10 @@ import {MultiParty} from './MultiParty'
type Props = {
transaction: TransactionInfo
size?: number
+ containerStyle?: ViewStyle
}
-export const Direction = ({transaction, size = defaultSize}: Props) => {
+export const Direction = ({transaction, size = defaultSize, containerStyle}: Props) => {
const {color} = useTheme()
const {direction} = transaction
@@ -21,7 +22,7 @@ export const Direction = ({transaction, size = defaultSize}: Props) => {
const IconComponent = iconMap[direction]
return (
-
+
)
diff --git a/apps/wallet-mobile/src/components/Info/Info.tsx b/apps/wallet-mobile/src/components/Info/Info.tsx
new file mode 100644
index 0000000000..b4272cc14e
--- /dev/null
+++ b/apps/wallet-mobile/src/components/Info/Info.tsx
@@ -0,0 +1,47 @@
+import {useTheme} from '@yoroi/theme'
+import React, {ReactNode} from 'react'
+import {StyleSheet, Text, View} from 'react-native'
+
+import {Icon} from '../Icon'
+import {Space} from '../Space/Space'
+
+type Props = {
+ content: ReactNode
+ iconSize?: number
+}
+
+export const Info = ({content, iconSize = 30}: Props) => {
+ const {styles, colors} = useStyles()
+
+ return (
+
+
+
+
+
+ {content}
+
+ )
+}
+
+const useStyles = () => {
+ const {color, atoms} = useTheme()
+ const styles = StyleSheet.create({
+ notice: {
+ backgroundColor: color.sys_cyan_100,
+ ...atoms.p_md,
+ ...atoms.rounded_sm,
+ },
+ text: {
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_max,
+ },
+ })
+
+ const colors = {
+ yellow: color.sys_orange_500,
+ blue: color.primary_500,
+ }
+
+ return {colors, styles} as const
+}
diff --git a/apps/wallet-mobile/src/features/Portfolio/common/MediaPreview/MediaPreview.tsx b/apps/wallet-mobile/src/components/MediaPreview/MediaPreview.tsx
similarity index 90%
rename from apps/wallet-mobile/src/features/Portfolio/common/MediaPreview/MediaPreview.tsx
rename to apps/wallet-mobile/src/components/MediaPreview/MediaPreview.tsx
index 8dacd28a7c..36f43371e1 100644
--- a/apps/wallet-mobile/src/features/Portfolio/common/MediaPreview/MediaPreview.tsx
+++ b/apps/wallet-mobile/src/components/MediaPreview/MediaPreview.tsx
@@ -5,9 +5,9 @@ import React from 'react'
import {ImageStyle, StyleSheet, View} from 'react-native'
import SkeletonPlaceholder from 'react-native-skeleton-placeholder'
-import placeholderLight from '../../../../assets/img/nft-placeholder.png'
-import placeholderDark from '../../../../assets/img/nft-placeholder-dark.png'
-import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet'
+import placeholderLight from '../../assets/img/nft-placeholder.png'
+import placeholderDark from '../../assets/img/nft-placeholder-dark.png'
+import {useSelectedWallet} from '../../features/WalletManager/common/hooks/useSelectedWallet'
type MediaPreviewProps = {
info: Portfolio.Token.Info
diff --git a/apps/wallet-mobile/src/components/SimpleTab/SimpleTab.stories.tsx b/apps/wallet-mobile/src/components/SimpleTab/SimpleTab.stories.tsx
new file mode 100644
index 0000000000..549ead2f95
--- /dev/null
+++ b/apps/wallet-mobile/src/components/SimpleTab/SimpleTab.stories.tsx
@@ -0,0 +1,26 @@
+import {action} from '@storybook/addon-actions'
+import {storiesOf} from '@storybook/react-native'
+import * as React from 'react'
+import {View} from 'react-native'
+
+import {SimpleTab} from './SimpleTab'
+
+storiesOf('SimpleTab', module)
+ .add('Active', () => )
+ .add('Inactive', () => )
+
+const Active = () => {
+ return (
+
+
+
+ )
+}
+
+const Inactive = () => {
+ return (
+
+
+
+ )
+}
diff --git a/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/DAppExplorerTabItem/DAppExplorerTabItem.tsx b/apps/wallet-mobile/src/components/SimpleTab/SimpleTab.tsx
similarity index 89%
rename from apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/DAppExplorerTabItem/DAppExplorerTabItem.tsx
rename to apps/wallet-mobile/src/components/SimpleTab/SimpleTab.tsx
index e140c97e43..e72787c55d 100644
--- a/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/DAppExplorerTabItem/DAppExplorerTabItem.tsx
+++ b/apps/wallet-mobile/src/components/SimpleTab/SimpleTab.tsx
@@ -8,7 +8,7 @@ type Props = {
onPress: () => void
}
-export const DAppExplorerTabItem = ({name, onPress, isActive}: Props) => {
+export const SimpleTab = ({name, onPress, isActive}: Props) => {
const {styles} = useStyles()
return (
@@ -34,5 +34,5 @@ const useStyles = () => {
},
})
- return {styles}
+ return {styles} as const
}
diff --git a/apps/wallet-mobile/src/components/Warning/Warning.tsx b/apps/wallet-mobile/src/components/Warning/Warning.tsx
index 320ee76732..ce1a959985 100644
--- a/apps/wallet-mobile/src/components/Warning/Warning.tsx
+++ b/apps/wallet-mobile/src/components/Warning/Warning.tsx
@@ -5,7 +5,10 @@ import {StyleSheet, Text, View} from 'react-native'
import {Icon} from '../Icon'
import {Space} from '../Space/Space'
-type Props = {content: ReactNode; iconSize?: number}
+type Props = {
+ content: ReactNode
+ iconSize?: number
+}
export const Warning = ({content, iconSize = 30}: Props) => {
const {styles, colors} = useStyles()
@@ -26,8 +29,8 @@ const useStyles = () => {
const styles = StyleSheet.create({
notice: {
backgroundColor: color.sys_yellow_100,
- padding: 12,
- borderRadius: 8,
+ ...atoms.p_md,
+ ...atoms.rounded_sm,
},
text: {
...atoms.body_2_md_regular,
@@ -39,5 +42,5 @@ const useStyles = () => {
yellow: color.sys_orange_500,
}
- return {colors, styles}
+ return {colors, styles} as const
}
diff --git a/apps/wallet-mobile/src/features/Discover/useCases/ReviewTransaction/ReviewTransaction.tsx b/apps/wallet-mobile/src/features/Discover/useCases/ReviewTransaction/ReviewTransaction.tsx
index bfbf280cd5..2bd93f55f2 100644
--- a/apps/wallet-mobile/src/features/Discover/useCases/ReviewTransaction/ReviewTransaction.tsx
+++ b/apps/wallet-mobile/src/features/Discover/useCases/ReviewTransaction/ReviewTransaction.tsx
@@ -447,7 +447,7 @@ const useConnectorPromptRootKey = () => {
}, [promptRootKey])
}
-const useSignTxWithHW = () => {
+export const useSignTxWithHW = () => {
const {confirmHWConnection, closeModal} = useConfirmHWConnectionModal()
const {wallet, meta} = useSelectedWallet()
diff --git a/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/DAppExplorerTabItem/DAppExplorerTabItem.stories.tsx b/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/DAppExplorerTabItem/DAppExplorerTabItem.stories.tsx
deleted file mode 100644
index 626ac02ba0..0000000000
--- a/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/DAppExplorerTabItem/DAppExplorerTabItem.stories.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import {action} from '@storybook/addon-actions'
-import {storiesOf} from '@storybook/react-native'
-import * as React from 'react'
-import {View} from 'react-native'
-
-import {DAppExplorerTabItem} from './DAppExplorerTabItem'
-
-storiesOf('Discover DAppExplorerTabItem', module)
- .add('connected', () => )
- .add('recommended', () => )
-
-const Connected = () => {
- return (
-
-
-
- )
-}
-
-const Recommended = () => {
- return (
-
-
-
- )
-}
diff --git a/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/SelectDappFromListScreen.tsx b/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/SelectDappFromListScreen.tsx
index a21de2ae63..39a2ee4b6c 100644
--- a/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/SelectDappFromListScreen.tsx
+++ b/apps/wallet-mobile/src/features/Discover/useCases/SelectDappFromList/SelectDappFromListScreen.tsx
@@ -3,6 +3,7 @@ import {useTheme} from '@yoroi/theme'
import * as React from 'react'
import {FlatList, StyleSheet, View} from 'react-native'
+import {SimpleTab} from '../../../../components/SimpleTab/SimpleTab'
import {Spacer} from '../../../../components/Spacer/Spacer'
import {useMetrics} from '../../../../kernel/metrics/metricsManager'
import {useSearch, useSearchOnNavBar} from '../../../Search/SearchContext'
@@ -13,7 +14,6 @@ import {useDAppsConnected} from '../../common/useDAppsConnected'
import {useStrings} from '../../common/useStrings'
import {CountDAppsAvailable} from './CountDAppsAvailable/CountDAppsAvailable'
import {CountDAppsConnected} from './CountDAppsConnected/CountDAppsConnected'
-import {DAppExplorerTabItem} from './DAppExplorerTabItem/DAppExplorerTabItem'
import {DAppListItem} from './DAppListItem/DAppListItem'
import {DAppTypes} from './DAppTypes/DAppTypes'
import {WelcomeDAppModal} from './WelcomeDAppModal'
@@ -153,13 +153,13 @@ const HeaderControl = ({
<>
{hasConnectedDapps && (
- onTabChange(DAppTabs.connected)}
/>
- onTabChange(DAppTabs.recommended)}
diff --git a/apps/wallet-mobile/src/features/Portfolio/common/MediaDetailsScreen/MediaDetailsScreen.tsx b/apps/wallet-mobile/src/features/Portfolio/common/MediaDetailsScreen/MediaDetailsScreen.tsx
index bcd4e24f25..f2cff3c32c 100644
--- a/apps/wallet-mobile/src/features/Portfolio/common/MediaDetailsScreen/MediaDetailsScreen.tsx
+++ b/apps/wallet-mobile/src/features/Portfolio/common/MediaDetailsScreen/MediaDetailsScreen.tsx
@@ -20,6 +20,7 @@ import {Boundary} from '../../../../components/Boundary/Boundary'
import {CopyButton} from '../../../../components/CopyButton'
import {FadeIn} from '../../../../components/FadeIn'
import {Hr} from '../../../../components/Hr/Hr'
+import {MediaPreview} from '../../../../components/MediaPreview/MediaPreview'
import {Spacer} from '../../../../components/Spacer/Spacer'
import {Tab, TabPanel, TabPanels, Tabs} from '../../../../components/Tabs/Tabs'
import {Text} from '../../../../components/Text'
@@ -28,7 +29,6 @@ import {useMetrics} from '../../../../kernel/metrics/metricsManager'
import {NftRoutes} from '../../../../kernel/navigation'
import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet'
import {usePortfolioImageInvalidate} from '../hooks/usePortfolioImage'
-import {MediaPreview} from '../MediaPreview/MediaPreview'
import {useNavigateTo} from '../navigation'
export const MediaDetailsScreen = () => {
diff --git a/apps/wallet-mobile/src/features/Portfolio/common/MediaGallery/MediaGallery.tsx b/apps/wallet-mobile/src/features/Portfolio/common/MediaGallery/MediaGallery.tsx
index 149d062a5f..273b193caf 100644
--- a/apps/wallet-mobile/src/features/Portfolio/common/MediaGallery/MediaGallery.tsx
+++ b/apps/wallet-mobile/src/features/Portfolio/common/MediaGallery/MediaGallery.tsx
@@ -4,8 +4,8 @@ import {Balance, Portfolio} from '@yoroi/types'
import * as React from 'react'
import {StyleSheet, Text, TouchableOpacity, useWindowDimensions, View} from 'react-native'
+import {MediaPreview} from '../../../../components/MediaPreview/MediaPreview'
import {Spacer} from '../../../../components/Spacer/Spacer'
-import {MediaPreview} from '../MediaPreview/MediaPreview'
type Props = {
amounts: ReadonlyArray
diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioDashboard/DashboardNFTsList/DashboardNFTsList.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioDashboard/DashboardNFTsList/DashboardNFTsList.tsx
index d60950805a..a3e6402aa3 100644
--- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioDashboard/DashboardNFTsList/DashboardNFTsList.tsx
+++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioDashboard/DashboardNFTsList/DashboardNFTsList.tsx
@@ -5,12 +5,12 @@ import {FlatList, Image, StyleSheet, Text, TouchableOpacity, useWindowDimensions
import placeholderLight from '../../../../../assets/img/nft-placeholder.png'
import placeholderDark from '../../../../../assets/img/nft-placeholder-dark.png'
import {Icon} from '../../../../../components/Icon'
+import {MediaPreview} from '../../../../../components/MediaPreview/MediaPreview'
import {Spacer} from '../../../../../components/Spacer/Spacer'
import {useSelectedWallet} from '../../../../WalletManager/common/hooks/useSelectedWallet'
import {useNavigateTo} from '../../../common/hooks/useNavigateTo'
import {usePortfolioBalances} from '../../../common/hooks/usePortfolioBalances'
import {useStrings} from '../../../common/hooks/useStrings'
-import {MediaPreview} from '../../../common/MediaPreview/MediaPreview'
export const DashboardNFTsList = () => {
const {styles, cardItemWidth} = useStyles()
diff --git a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokensList/PortfolioWalletTokenList/ListMediaGalleryScreen/ZoomMediaImageScreen.tsx b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokensList/PortfolioWalletTokenList/ListMediaGalleryScreen/ZoomMediaImageScreen.tsx
index fc4fdb9071..b655b30e32 100644
--- a/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokensList/PortfolioWalletTokenList/ListMediaGalleryScreen/ZoomMediaImageScreen.tsx
+++ b/apps/wallet-mobile/src/features/Portfolio/useCases/PortfolioTokensList/PortfolioWalletTokenList/ListMediaGalleryScreen/ZoomMediaImageScreen.tsx
@@ -6,11 +6,11 @@ import {StyleSheet, useWindowDimensions, View} from 'react-native'
import ViewTransformer from 'react-native-easy-view-transformer'
import {FadeIn} from '../../../../../../components/FadeIn'
+import {MediaPreview} from '../../../../../../components/MediaPreview/MediaPreview'
import {useMetrics} from '../../../../../../kernel/metrics/metricsManager'
import {NftRoutes, useParams} from '../../../../../../kernel/navigation'
import {isEmptyString} from '../../../../../../kernel/utils'
import {useSelectedWallet} from '../../../../../WalletManager/common/hooks/useSelectedWallet'
-import {MediaPreview} from '../../../../common/MediaPreview/MediaPreview'
type Params = NftRoutes['nft-details']
diff --git a/apps/wallet-mobile/src/features/ReviewTx/ReviewTxNavigator.tsx b/apps/wallet-mobile/src/features/ReviewTx/ReviewTxNavigator.tsx
new file mode 100644
index 0000000000..4f28322aff
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/ReviewTxNavigator.tsx
@@ -0,0 +1,36 @@
+import {createStackNavigator} from '@react-navigation/stack'
+import {Atoms, ThemedPalette, useTheme} from '@yoroi/theme'
+import React from 'react'
+
+import {Boundary} from '../../components/Boundary/Boundary'
+import {defaultStackNavigationOptions, ReviewTxRoutes} from '../../kernel/navigation'
+import {useStrings} from './common/hooks/useStrings'
+import {ReviewTxScreen} from './useCases/ReviewTxScreen/ReviewTxScreen'
+
+export const Stack = createStackNavigator()
+
+export const ReviewTxNavigator = () => {
+ const {atoms, color} = useTheme()
+ const strings = useStrings()
+
+ return (
+
+
+ {() => (
+
+
+
+ )}
+
+
+ )
+}
+
+const screenOptions = (atoms: Atoms, color: ThemedPalette) => ({
+ ...defaultStackNavigationOptions(atoms, color),
+ gestureEnabled: true,
+})
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/Accordion.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/Accordion.tsx
new file mode 100644
index 0000000000..92e7bfb3ac
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/Accordion.tsx
@@ -0,0 +1,69 @@
+import {useTheme} from '@yoroi/theme'
+import * as React from 'react'
+import {Animated, LayoutAnimation, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
+
+import {Icon} from '../../../components/Icon'
+
+export const Accordion = ({label, children}: {label: string; children: React.ReactNode}) => {
+ const {styles, colors} = useStyles()
+ const [isOpen, setIsOpen] = React.useState(false)
+ const animatedHeight = React.useRef(new Animated.Value(0)).current
+
+ const toggleSection = () => {
+ LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
+ setIsOpen(!isOpen)
+ Animated.timing(animatedHeight, {
+ toValue: isOpen ? 0 : 1,
+ duration: 300,
+ useNativeDriver: false,
+ }).start()
+ }
+
+ return (
+
+
+ {label}
+
+
+
+
+
+ {children}
+
+
+ )
+}
+
+const useStyles = () => {
+ const {atoms, color} = useTheme()
+ const styles = StyleSheet.create({
+ sectionHeader: {
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ },
+ sectionHeaderText: {
+ ...atoms.body_1_lg_medium,
+ color: color.text_gray_medium,
+ },
+ childrenContainer: {
+ overflow: 'hidden',
+ },
+ })
+
+ const colors = {
+ chevron: color.gray_900,
+ }
+
+ return {styles, colors} as const
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/CopiableText.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/CopiableText.tsx
new file mode 100644
index 0000000000..b09812b5a6
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/CopiableText.tsx
@@ -0,0 +1,37 @@
+import {useTheme} from '@yoroi/theme'
+import * as React from 'react'
+import {StyleSheet, TouchableOpacity, View} from 'react-native'
+
+import {Icon} from '../../../components/Icon'
+import {useCopy} from '../../../hooks/useCopy'
+
+export const CopiableText = ({children, textToCopy}: {children: React.ReactNode; textToCopy: string}) => {
+ const {styles, colors} = useStyles()
+ const [, copy] = useCopy()
+
+ return (
+
+ {children}
+
+ copy(textToCopy)} activeOpacity={0.5}>
+
+
+
+ )
+}
+
+const useStyles = () => {
+ const {atoms, color} = useTheme()
+ const styles = StyleSheet.create({
+ text: {
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ },
+ })
+
+ const colors = {
+ copy: color.gray_900,
+ }
+
+ return {styles, colors} as const
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/Divider.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/Divider.tsx
new file mode 100644
index 0000000000..1733930fda
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/Divider.tsx
@@ -0,0 +1,31 @@
+import {SpacingSize, useTheme} from '@yoroi/theme'
+import * as React from 'react'
+import {StyleSheet, View} from 'react-native'
+
+import {Space} from '../../../components/Space/Space'
+
+export const Divider = ({verticalSpace = 'none'}: {verticalSpace?: SpacingSize}) => {
+ const {styles} = useStyles()
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+}
+
+const useStyles = () => {
+ const {atoms, color} = useTheme()
+ const styles = StyleSheet.create({
+ divider: {
+ height: 1,
+ ...atoms.align_stretch,
+ backgroundColor: color.gray_200,
+ },
+ })
+
+ return {styles} as const
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/ReviewTxProvider.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/ReviewTxProvider.tsx
new file mode 100644
index 0000000000..05dd6ec924
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/ReviewTxProvider.tsx
@@ -0,0 +1,141 @@
+import {castDraft, produce} from 'immer'
+import _ from 'lodash'
+import React from 'react'
+
+import {YoroiSignedTx, YoroiUnsignedTx} from '../../../yoroi-wallets/types/yoroi'
+
+export const useReviewTx = () => React.useContext(ReviewTxContext)
+
+export const ReviewTxProvider = ({
+ children,
+ initialState,
+}: {
+ children: React.ReactNode
+ initialState?: Partial
+}) => {
+ const [state, dispatch] = React.useReducer(reviewTxReducer, {
+ ...defaultState,
+ ...initialState,
+ })
+
+ const actions = React.useRef({
+ unsignedTxChanged: (unsignedTx: ReviewTxState['unsignedTx']) =>
+ dispatch({type: ReviewTxActionType.UnsignedTxChanged, unsignedTx}),
+ cborChanged: (cbor: ReviewTxState['cbor']) => dispatch({type: ReviewTxActionType.CborChanged, cbor}),
+ operationsChanged: (operations: ReviewTxState['operations']) =>
+ dispatch({type: ReviewTxActionType.OperationsChanged, operations}),
+ onSuccessChanged: (onSuccess: ReviewTxState['onSuccess']) =>
+ dispatch({type: ReviewTxActionType.OnSuccessChanged, onSuccess}),
+ onErrorChanged: (onError: ReviewTxState['onError']) => dispatch({type: ReviewTxActionType.OnErrorChanged, onError}),
+ }).current
+
+ const context = React.useMemo(
+ () => ({
+ ...state,
+ ...actions,
+ }),
+ [state, actions],
+ )
+
+ return {children}
+}
+
+const reviewTxReducer = (state: ReviewTxState, action: ReviewTxAction) => {
+ return produce(state, (draft) => {
+ switch (action.type) {
+ case ReviewTxActionType.UnsignedTxChanged:
+ draft.unsignedTx = castDraft(action.unsignedTx)
+ break
+
+ case ReviewTxActionType.CborChanged:
+ draft.cbor = action.cbor
+ break
+
+ case ReviewTxActionType.OperationsChanged:
+ draft.operations = action.operations
+ break
+
+ case ReviewTxActionType.OnSuccessChanged:
+ draft.onSuccess = action.onSuccess
+ break
+
+ case ReviewTxActionType.OnErrorChanged:
+ draft.onError = action.onError
+ break
+
+ default:
+ throw new Error('[ReviewTxContext] invalid action')
+ }
+ })
+}
+
+type ReviewTxAction =
+ | {
+ type: ReviewTxActionType.UnsignedTxChanged
+ unsignedTx: ReviewTxState['unsignedTx']
+ }
+ | {
+ type: ReviewTxActionType.CborChanged
+ cbor: ReviewTxState['cbor']
+ }
+ | {
+ type: ReviewTxActionType.OperationsChanged
+ operations: ReviewTxState['operations']
+ }
+ | {
+ type: ReviewTxActionType.OnSuccessChanged
+ onSuccess: ReviewTxState['onSuccess']
+ }
+ | {
+ type: ReviewTxActionType.OnErrorChanged
+ onError: ReviewTxState['onError']
+ }
+
+export type ReviewTxState = {
+ unsignedTx: YoroiUnsignedTx | null
+ cbor: string | null
+ operations: Array | null
+ onSuccess: ((signedTx: YoroiSignedTx) => void) | null
+ onError: (() => void) | null
+}
+
+type ReviewTxActions = {
+ unsignedTxChanged: (unsignedTx: ReviewTxState['unsignedTx']) => void
+ cborChanged: (cbor: ReviewTxState['cbor']) => void
+ operationsChanged: (operations: ReviewTxState['operations']) => void
+ onSuccessChanged: (onSuccess: ReviewTxState['onSuccess']) => void
+ onErrorChanged: (onError: ReviewTxState['onError']) => void
+}
+
+const defaultState: ReviewTxState = Object.freeze({
+ unsignedTx: null,
+ cbor: null,
+ operations: null,
+ onSuccess: null,
+ onError: null,
+})
+
+function missingInit() {
+ console.error('[ReviewTxContext] missing initialization')
+}
+
+const initialReviewTxContext: ReviewTxContext = {
+ ...defaultState,
+ unsignedTxChanged: missingInit,
+ cborChanged: missingInit,
+ operationsChanged: missingInit,
+ onSuccessChanged: missingInit,
+ onErrorChanged: missingInit,
+}
+
+enum ReviewTxActionType {
+ UnsignedTxChanged = 'unsignedTxChanged',
+ CborChanged = 'cborChanged',
+ OperationsChanged = 'operationsChanged',
+ OnSuccessChanged = 'onSuccessChanged',
+ OnErrorChanged = 'onErrorChanged',
+}
+
+type ReviewTxContext = ReviewTxState & ReviewTxActions
+
+const ReviewTxContext = React.createContext(initialReviewTxContext)
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/TokenDetails.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/TokenDetails.tsx
new file mode 100644
index 0000000000..6f590decfa
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/TokenDetails.tsx
@@ -0,0 +1,396 @@
+import {usePortfolioTokenDiscovery} from '@yoroi/portfolio'
+import {useTheme} from '@yoroi/theme'
+import {Portfolio} from '@yoroi/types'
+import * as React from 'react'
+import {Linking, ScrollView, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
+
+import {Icon} from '../../../components/Icon'
+import {MediaPreview} from '../../../components/MediaPreview/MediaPreview'
+import {SimpleTab} from '../../../components/SimpleTab/SimpleTab'
+import {Space} from '../../../components/Space/Space'
+import {useCopy} from '../../../hooks/useCopy'
+import {time} from '../../../kernel/constants'
+import {isEmptyString} from '../../../kernel/utils'
+import {useSelectedWallet} from '../../WalletManager/common/hooks/useSelectedWallet'
+import {CopiableText} from './CopiableText'
+import {useStrings} from './hooks/useStrings'
+
+export const TokenDetails = ({tokenInfo}: {tokenInfo: Portfolio.Token.Info}) => {
+ const {styles} = useStyles()
+
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+const Header = ({info}: {info: Portfolio.Token.Info}) => {
+ const {styles} = useStyles()
+ const [policyId, assetName] = info.id.split('.')
+
+ const title = !isEmptyString(info.ticker) ? info.ticker : !isEmptyString(info.name) ? info.name : ''
+
+ return (
+
+
+
+
+
+ {!isEmptyString(title) && {title}}
+
+ {`(${assetName})`}
+
+
+
+
+
+
+
+
+
+ )
+}
+
+const Info = ({info}: {info: Portfolio.Token.Info}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+ const {wallet} = useSelectedWallet()
+ const [activeTab, setActiveTab] = React.useState<'overview' | 'json'>('overview')
+
+ const {tokenDiscovery} = usePortfolioTokenDiscovery(
+ {
+ id: info.id,
+ network: wallet.networkManager.network,
+ getTokenDiscovery: wallet.networkManager.tokenManager.api.tokenDiscovery,
+ },
+ {
+ staleTime: time.session,
+ },
+ )
+
+ return (
+
+
+ setActiveTab('overview')}
+ isActive={activeTab === 'overview'}
+ />
+
+ setActiveTab('json')} isActive={activeTab === 'json'} />
+
+
+
+
+ {/* ↓↓↓ TABS CONTENT ↓↓↓ */}
+
+
+
+
+
+ )
+}
+
+const Json = ({discovery, isActive}: {discovery?: Portfolio.Token.Discovery; isActive: boolean}) => {
+ const {styles, colors} = useStyles()
+ const strings = useStrings()
+ const [, copy] = useCopy()
+
+ if (!isActive || !discovery) return null
+
+ const stringifiedMetadata = JSON.stringify(discovery.originalMetadata, null, 2)
+
+ return (
+
+
+ {strings.metadata}
+
+ copy(stringifiedMetadata)} activeOpacity={0.5}>
+
+
+
+
+
+
+
+ {stringifiedMetadata}
+
+
+ )
+}
+
+const Overview = ({
+ info,
+ discovery,
+ isActive,
+}: {
+ info: Portfolio.Token.Info
+ discovery?: Portfolio.Token.Discovery
+ isActive: boolean
+}) => {
+ if (!isActive) return null
+
+ if (info.type === 'ft') {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+const PolicyId = ({policyId}: {policyId: string}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ if (isEmptyString(policyId)) return null
+
+ return (
+
+ {strings.policyId}
+
+
+
+
+
+ {policyId}
+
+
+
+ )
+}
+
+const Fingerprint = ({info}: {info: Portfolio.Token.Info}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ if (isEmptyString(info.fingerprint)) return null
+
+ return (
+
+ {strings.fingerprint}
+
+
+
+
+
+ {info.fingerprint}
+
+
+
+ )
+}
+
+const Name = ({info}: {info: Portfolio.Token.Info}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ if (isEmptyString(info.name)) return null
+
+ return (
+
+ {strings.name}
+
+ {info.name}
+
+ )
+}
+
+const TokenSupply = ({discovery}: {discovery?: Portfolio.Token.Discovery}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ if (!discovery || isEmptyString(discovery.supply)) return null
+
+ return (
+
+
+
+
+ {strings.tokenSupply}
+
+ {discovery.supply}
+
+
+ )
+}
+
+const Symbol = ({info}: {info: Portfolio.Token.Info}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ if (isEmptyString(info.ticker)) return null
+
+ return (
+
+
+
+
+ {strings.symbol}
+
+ {info.ticker}
+
+
+ )
+}
+
+const Description = ({info}: {info: Portfolio.Token.Info}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ if (isEmptyString(info.description)) return null
+
+ return (
+
+
+
+ {strings.description}
+
+ {info.description}
+
+ )
+}
+
+const Links = ({info}: {info: Portfolio.Token.Info}) => {
+ const {styles} = useStyles()
+ const {wallet} = useSelectedWallet()
+ const strings = useStrings()
+
+ const handleOpenLink = async (direction: 'cardanoscan' | 'adaex') => {
+ if (info == null) return
+ if (direction === 'cardanoscan') {
+ await Linking.openURL(wallet.networkManager.explorers.cardanoscan.token(info.id))
+ } else {
+ await Linking.openURL(wallet.networkManager.explorers.cexplorer.token(info.id))
+ }
+ }
+
+ return (
+
+
+
+ {strings.details}
+
+
+ handleOpenLink('cardanoscan')}>
+ Cardanoscan
+
+
+ handleOpenLink('adaex')}>
+ Adaex
+
+
+
+ )
+}
+
+const Row = ({children}: {children: React.ReactNode}) => {
+ const {styles} = useStyles()
+ return {children}
+}
+
+const useStyles = () => {
+ const {atoms, color} = useTheme()
+
+ const styles = StyleSheet.create({
+ root: {
+ ...atoms.flex_1,
+ ...atoms.px_lg,
+ },
+ header: {
+ ...atoms.align_center,
+ },
+ headerText: {
+ ...atoms.body_1_lg_medium,
+ ...atoms.text_center,
+ color: color.text_gray_medium,
+ maxWidth: 300,
+ },
+ row: {
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ },
+ label: {
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_low,
+ },
+ value: {
+ ...atoms.flex_1,
+ ...atoms.text_right,
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_max,
+ },
+ description: {
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_max,
+ },
+ tabs: {
+ ...atoms.flex_row,
+ },
+ link: {
+ ...atoms.link_1_lg_underline,
+ color: color.text_primary_medium,
+ },
+ linkGroup: {
+ ...atoms.flex_row,
+ ...atoms.gap_lg,
+ },
+ copiableText: {
+ ...atoms.flex_1,
+ ...atoms.align_center,
+ },
+ json: {
+ ...atoms.flex_1,
+ ...atoms.pt_lg,
+ borderRadius: 8,
+ backgroundColor: color.bg_color_min,
+ },
+ jsonHeader: {
+ ...atoms.px_lg,
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ },
+ jsonLabel: {
+ ...atoms.body_1_lg_medium,
+ color: color.text_gray_medium,
+ },
+ jsonContent: {
+ ...atoms.px_lg,
+ },
+ info: {
+ ...atoms.flex_1,
+ },
+ metadata: {
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_medium,
+ },
+ })
+
+ const colors = {
+ copy: color.gray_900,
+ }
+
+ return {styles, colors} as const
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/TokenItem.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/TokenItem.tsx
new file mode 100644
index 0000000000..fabea93b81
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/TokenItem.tsx
@@ -0,0 +1,100 @@
+import {useTheme} from '@yoroi/theme'
+import {Portfolio} from '@yoroi/types'
+import * as React from 'react'
+import {StyleSheet, Text, TouchableOpacity, useWindowDimensions} from 'react-native'
+
+import {useModal} from '../../../components/Modal/ModalContext'
+import {useStrings} from './hooks/useStrings'
+import {TokenDetails} from './TokenDetails'
+
+export const TokenItem = ({
+ tokenInfo,
+ isPrimaryToken = true,
+ isSent = true,
+ label,
+}: {
+ tokenInfo: Portfolio.Token.Info
+ isPrimaryToken?: boolean
+ isSent?: boolean
+ label: string
+}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+ const {openModal} = useModal()
+ const {height: windowHeight} = useWindowDimensions()
+
+ const handleShowTokenDetails = () => {
+ openModal(strings.tokenDetailsTitle, , windowHeight * 0.8)
+ }
+
+ if (!isSent)
+ return (
+
+
+ {label}
+
+
+ )
+
+ return (
+
+ {label}
+
+ )
+}
+
+const useStyles = () => {
+ const {atoms, color} = useTheme()
+ const styles = StyleSheet.create({
+ sentTokenItem: {
+ ...atoms.flex,
+ ...atoms.flex_row,
+ ...atoms.align_center,
+ ...atoms.py_xs,
+ ...atoms.px_md,
+ borderRadius: 8,
+ backgroundColor: color.primary_500,
+ },
+ receivedTokenItem: {
+ ...atoms.flex,
+ ...atoms.flex_row,
+ ...atoms.align_center,
+ ...atoms.py_xs,
+ ...atoms.px_md,
+ borderRadius: 8,
+ backgroundColor: color.secondary_300,
+ },
+ tokenSentItemText: {
+ ...atoms.body_2_md_regular,
+ color: color.white_static,
+ },
+ tokenReceivedItemText: {
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_max,
+ },
+ notPrimarySentTokenItem: {
+ backgroundColor: color.primary_100,
+ },
+ notPrimaryReceivedTokenItem: {
+ backgroundColor: color.secondary_100,
+ },
+ notPrimarySentTokenItemText: {
+ color: color.text_primary_medium,
+ },
+ notPrimaryReceivedTokenItemText: {
+ color: color.secondary_700,
+ },
+ })
+
+ return {styles} as const
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useAddressType.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useAddressType.tsx
new file mode 100644
index 0000000000..6e054df944
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useAddressType.tsx
@@ -0,0 +1,12 @@
+import {useQuery} from 'react-query'
+
+import {getAddressType} from '../../../../yoroi-wallets/cardano/utils'
+
+export const useAddressType = (address: string) => {
+ const query = useQuery(['useAddressType', address], () => getAddressType(address), {
+ suspense: true,
+ })
+
+ if (query.data === undefined) throw new Error('invalid address type')
+ return query.data
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx
new file mode 100644
index 0000000000..7949d9541d
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx
@@ -0,0 +1,230 @@
+import {invalid, isNonNullable} from '@yoroi/common'
+import {infoExtractName} from '@yoroi/portfolio'
+import {Portfolio} from '@yoroi/types'
+import _ from 'lodash'
+import {useQuery} from 'react-query'
+
+import {YoroiWallet} from '../../../../yoroi-wallets/cardano/types'
+import {wrappedCsl} from '../../../../yoroi-wallets/cardano/wrappedCsl'
+import {formatTokenWithText} from '../../../../yoroi-wallets/utils/format'
+import {asQuantity} from '../../../../yoroi-wallets/utils/utils'
+import {usePortfolioTokenInfos} from '../../../Portfolio/common/hooks/usePortfolioTokenInfos'
+import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet'
+import {
+ FormattedFee,
+ FormattedInputs,
+ FormattedOutputs,
+ TransactionBody,
+ TransactionInputs,
+ TransactionOutputs,
+} from '../types'
+
+export const useFormattedTx = (data: TransactionBody) => {
+ const {wallet} = useSelectedWallet()
+
+ const inputs = data?.inputs ?? []
+ const outputs = data?.outputs ?? []
+
+ const inputTokenIds = inputs.flatMap((i) => {
+ const receiveUTxO = getUtxoByTxIdAndIndex(wallet, i.transaction_id, i.index)
+ return receiveUTxO?.assets.map((a) => `${a.policyId}.${a.assetId}` as Portfolio.Token.Id) ?? []
+ })
+
+ const outputTokenIds = outputs.flatMap((o) => {
+ if (!o.amount.multiasset) return []
+ const policyIds = Object.keys(o.amount.multiasset)
+ const tokenIds = policyIds.flatMap((policyId) => {
+ const assetIds = Object.keys(o.amount.multiasset?.[policyId] ?? {})
+ return assetIds.map((assetId) => `${policyId}.${assetId}` as Portfolio.Token.Id)
+ })
+ return tokenIds
+ })
+
+ const tokenIds = _.uniq([...inputTokenIds, ...outputTokenIds])
+ const portfolioTokenInfos = usePortfolioTokenInfos({wallet, tokenIds}, {suspense: true})
+
+ const formattedInputs = useFormattedInputs(wallet, inputs, portfolioTokenInfos)
+ const formattedOutputs = useFormattedOutputs(wallet, outputs, portfolioTokenInfos)
+ const formattedFee = formatFee(wallet, data)
+
+ return {inputs: formattedInputs, outputs: formattedOutputs, fee: formattedFee}
+}
+
+export const useFormattedInputs = (
+ wallet: YoroiWallet,
+ inputs: TransactionInputs,
+ tokenInfosResult: ReturnType,
+) => {
+ const query = useQuery(
+ ['useFormattedInputs', inputs],
+ async () => formatInputs(wallet, inputs, tokenInfosResult),
+ {
+ suspense: true,
+ },
+ )
+
+ if (!query.data) throw new Error('invalid formatted inputs')
+ return query.data
+}
+
+export const useFormattedOutputs = (
+ wallet: YoroiWallet,
+ outputs: TransactionOutputs,
+ portfolioTokenInfos: ReturnType,
+) => {
+ const query = useQuery(
+ ['useFormattedOutputs', outputs],
+ () => formatOutputs(wallet, outputs, portfolioTokenInfos),
+ {
+ suspense: true,
+ },
+ )
+
+ if (!query.data) throw new Error('invalid formatted outputs')
+ return query.data
+}
+
+const formatInputs = async (
+ wallet: YoroiWallet,
+ inputs: TransactionInputs,
+ portfolioTokenInfos: ReturnType,
+): Promise => {
+ return Promise.all(
+ inputs.map(async (input) => {
+ const receiveUTxO = getUtxoByTxIdAndIndex(wallet, input.transaction_id, input.index)
+ const address = receiveUTxO?.receiver
+ const rewardAddress =
+ address !== undefined ? await deriveRewardAddressFromAddress(address, wallet.networkManager.chainId) : null
+ const coin = receiveUTxO?.amount != null ? asQuantity(receiveUTxO.amount) : null
+
+ const primaryAssets =
+ coin != null
+ ? [
+ {
+ tokenInfo: wallet.portfolioPrimaryTokenInfo,
+ name: wallet.portfolioPrimaryTokenInfo.name,
+ label: formatTokenWithText(coin, wallet.portfolioPrimaryTokenInfo),
+ quantity: coin,
+ isPrimary: true,
+ },
+ ]
+ : []
+
+ const multiAssets =
+ receiveUTxO?.assets
+ .map((a) => {
+ const tokenInfo = portfolioTokenInfos.tokenInfos?.get(a.assetId as Portfolio.Token.Id)
+ if (!tokenInfo) return null
+ const quantity = asQuantity(a.amount)
+
+ return {
+ tokenInfo,
+ name: infoExtractName(tokenInfo),
+ label: formatTokenWithText(quantity, tokenInfo),
+ quantity: quantity,
+ isPrimary: false,
+ }
+ })
+ .filter(Boolean) ?? []
+
+ return {
+ assets: [...primaryAssets, ...multiAssets].filter(isNonNullable),
+ address,
+ rewardAddress,
+ ownAddress: address != null && isOwnedAddress(wallet, address),
+ txIndex: input.index,
+ txHash: input.transaction_id,
+ }
+ }),
+ )
+}
+
+const formatOutputs = async (
+ wallet: YoroiWallet,
+ outputs: TransactionOutputs,
+ portfolioTokenInfos: ReturnType,
+): Promise => {
+ return Promise.all(
+ outputs.map(async (output) => {
+ const address = output.address
+ const rewardAddress = await deriveRewardAddressFromAddress(address, wallet.networkManager.chainId)
+ const coin = asQuantity(output.amount.coin)
+
+ const primaryAssets = [
+ {
+ tokenInfo: wallet.portfolioPrimaryTokenInfo,
+ name: wallet.portfolioPrimaryTokenInfo.name,
+ label: formatTokenWithText(coin, wallet.portfolioPrimaryTokenInfo),
+ quantity: coin,
+ isPrimary: true,
+ },
+ ]
+
+ const multiAssets = output.amount.multiasset
+ ? Object.entries(output.amount.multiasset).flatMap(([policyId, assets]) => {
+ return Object.entries(assets).map(([assetId, amount]) => {
+ const tokenInfo = portfolioTokenInfos.tokenInfos?.get(`${policyId}.${assetId}`)
+ if (tokenInfo == null) return null
+ const quantity = asQuantity(amount)
+
+ return {
+ tokenInfo,
+ name: infoExtractName(tokenInfo),
+ label: formatTokenWithText(quantity, tokenInfo),
+ quantity,
+ isPrimary: false,
+ }
+ })
+ })
+ : []
+
+ const assets = [...primaryAssets, ...multiAssets].filter(isNonNullable)
+
+ return {
+ assets,
+ address,
+ rewardAddress,
+ ownAddress: isOwnedAddress(wallet, address),
+ }
+ }),
+ )
+}
+
+export const formatFee = (wallet: YoroiWallet, data: TransactionBody): FormattedFee => {
+ const fee = asQuantity(data?.fee ?? '0')
+
+ return {
+ tokenInfo: wallet.portfolioPrimaryTokenInfo,
+ name: wallet.portfolioPrimaryTokenInfo.name,
+ label: formatTokenWithText(fee, wallet.portfolioPrimaryTokenInfo),
+ quantity: fee,
+ isPrimary: true,
+ }
+}
+
+export const deriveRewardAddressFromAddress = async (address: string, chainId: number): Promise => {
+ const {csl, release} = wrappedCsl()
+
+ try {
+ const result = await csl.Address.fromBech32(address)
+ .then((address) => csl.BaseAddress.fromAddress(address))
+ .then((baseAddress) => baseAddress?.stakeCred() ?? invalid('invalid base address'))
+ .then((stakeCredential) => csl.RewardAddress.new(chainId, stakeCredential))
+ .then((rewardAddress) => rewardAddress.toAddress())
+ .then((rewardAddrAsAddress) => rewardAddrAsAddress.toBech32(undefined))
+ .catch((error) => error)
+
+ if (typeof result !== 'string') throw new Error('Its not possible to derive reward address')
+ return result
+ } finally {
+ release()
+ }
+}
+
+const getUtxoByTxIdAndIndex = (wallet: YoroiWallet, txId: string, index: number) => {
+ return wallet.utxos.find((u) => u.tx_hash === txId && u.tx_index === index)
+}
+
+const isOwnedAddress = (wallet: YoroiWallet, bech32Address: string) => {
+ return wallet.internalAddresses.includes(bech32Address) || wallet.externalAddresses.includes(bech32Address)
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useOnConfirm.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useOnConfirm.tsx
new file mode 100644
index 0000000000..38188b6e93
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useOnConfirm.tsx
@@ -0,0 +1,71 @@
+import * as React from 'react'
+
+import {ConfirmTxWithHwModal} from '../../../../components/ConfirmTxWithHwModal/ConfirmTxWithHwModal'
+import {ConfirmTxWithOsModal} from '../../../../components/ConfirmTxWithOsModal/ConfirmTxWithOsModal'
+import {ConfirmTxWithSpendingPasswordModal} from '../../../../components/ConfirmTxWithSpendingPasswordModal/ConfirmTxWithSpendingPasswordModal'
+import {useModal} from '../../../../components/Modal/ModalContext'
+import {YoroiSignedTx, YoroiUnsignedTx} from '../../../../yoroi-wallets/types/yoroi'
+import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet'
+import {useStrings} from './useStrings'
+
+// TODO: make it compatible with CBOR signing
+export const useOnConfirm = ({
+ unsignedTx,
+ onSuccess,
+ onError,
+ onNotSupportedCIP1694,
+}: {
+ onSuccess?: ((txId: YoroiSignedTx) => void) | null
+ onError?: (() => void) | null
+ cbor?: string
+ unsignedTx?: YoroiUnsignedTx
+ onNotSupportedCIP1694?: () => void
+}) => {
+ if (unsignedTx === undefined) throw new Error('useOnConfirm: unsignedTx missing')
+
+ const {meta} = useSelectedWallet()
+ const {openModal, closeModal} = useModal()
+ const strings = useStrings()
+
+ const onConfirm = () => {
+ if (meta.isHW) {
+ openModal(
+ strings.signTransaction,
+ onSuccess?.(signedTx)}
+ onNotSupportedCIP1694={onNotSupportedCIP1694}
+ />,
+ 400,
+ )
+ return
+ }
+
+ if (!meta.isHW && !meta.isEasyConfirmationEnabled) {
+ openModal(
+ strings.signTransaction,
+ onSuccess?.(signedTx)}
+ onError={onError ?? undefined}
+ />,
+ )
+ return
+ }
+
+ if (!meta.isHW && meta.isEasyConfirmationEnabled) {
+ openModal(
+ strings.signTransaction,
+ onSuccess?.(signedTx)}
+ onError={onError ?? undefined}
+ />,
+ )
+ return
+ }
+ }
+
+ return {onConfirm} as const
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx
new file mode 100644
index 0000000000..9914016ec2
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx
@@ -0,0 +1,139 @@
+import {defineMessages, useIntl} from 'react-intl'
+
+import {txLabels} from '../../../../kernel/i18n/global-messages'
+
+export const useStrings = () => {
+ const intl = useIntl()
+
+ return {
+ signTransaction: intl.formatMessage(txLabels.signingTx),
+ confirm: intl.formatMessage(messages.confirm),
+ title: intl.formatMessage(messages.title),
+ utxosTab: intl.formatMessage(messages.utxosTab),
+ overviewTab: intl.formatMessage(messages.overviewTab),
+ walletLabel: intl.formatMessage(messages.walletLabel),
+ feeLabel: intl.formatMessage(messages.feeLabel),
+ myWalletLabel: intl.formatMessage(messages.myWalletLabel),
+ sendLabel: intl.formatMessage(messages.sendLabel),
+ receiveToLabel: intl.formatMessage(messages.receiveToLabel),
+ receiveToScriptLabel: intl.formatMessage(messages.receiveToScriptLabel),
+ utxosInputsLabel: intl.formatMessage(messages.utxosInputsLabel),
+ utxosOutputsLabel: intl.formatMessage(messages.utxosOutputsLabel),
+ utxosYourAddressLabel: intl.formatMessage(messages.utxosYourAddressLabel),
+ utxosForeignAddressLabel: intl.formatMessage(messages.utxosForeignAddressLabel),
+ overview: intl.formatMessage(messages.overview),
+ json: intl.formatMessage(messages.json),
+ metadata: intl.formatMessage(messages.metadata),
+ policyId: intl.formatMessage(messages.policyId),
+ fingerprint: intl.formatMessage(messages.fingerprint),
+ name: intl.formatMessage(messages.name),
+ tokenSupply: intl.formatMessage(messages.tokenSupply),
+ symbol: intl.formatMessage(messages.symbol),
+ description: intl.formatMessage(messages.description),
+ details: intl.formatMessage(messages.details),
+ tokenDetailsTitle: intl.formatMessage(messages.tokenDetailsTitle),
+ }
+}
+
+const messages = defineMessages({
+ confirm: {
+ id: 'txReview.confirm',
+ defaultMessage: '!!!Confirm',
+ },
+ title: {
+ id: 'txReview.title',
+ defaultMessage: '!!!UTxOs',
+ },
+ utxosTab: {
+ id: 'txReview.tabLabel.utxos',
+ defaultMessage: '!!!UTxOs',
+ },
+ overviewTab: {
+ id: 'txReview.tabLabel.overview',
+ defaultMessage: '!!!Overview',
+ },
+ walletLabel: {
+ id: 'txReview.overview.wallet',
+ defaultMessage: '!!!Wallet',
+ },
+ feeLabel: {
+ id: 'txReview.fee',
+ defaultMessage: '!!!Fee',
+ },
+ myWalletLabel: {
+ id: 'txReview.overview.myWalletLabel',
+ defaultMessage: '!!!Your Wallet',
+ },
+ sendLabel: {
+ id: 'txReview.overview.sendLabel',
+ defaultMessage: '!!!Send',
+ },
+ receiveToLabel: {
+ id: 'txReview.overview.receiveToLabel',
+ defaultMessage: '!!!To',
+ },
+ receiveToScriptLabel: {
+ id: 'txReview.overview.receiveToScriptLabel',
+ defaultMessage: '!!!To script',
+ },
+ utxosInputsLabel: {
+ id: 'txReview.utxos.utxosInputsLabel',
+ defaultMessage: '!!!Inputs',
+ },
+ utxosOutputsLabel: {
+ id: 'txReview.utxos.utxosOutputsLabel',
+ defaultMessage: '!!!Outputs',
+ },
+ utxosYourAddressLabel: {
+ id: 'txReview.utxos.utxosYourAddressLabel',
+ defaultMessage: '!!!Your address',
+ },
+ utxosForeignAddressLabel: {
+ id: 'txReview.utxos.utxosForeignAddressLabel',
+ defaultMessage: '!!!Foreign address',
+ },
+ overview: {
+ id: 'txReview.tokenDetails.overViewTab.title',
+ defaultMessage: '!!!Overview',
+ },
+ json: {
+ id: 'txReview.tokenDetails.jsonTab.title',
+ defaultMessage: '!!!JSON',
+ },
+ metadata: {
+ id: 'txReview.tokenDetails.jsonTab.metadata',
+ defaultMessage: '!!!Metadata',
+ },
+ policyId: {
+ id: 'txReview.tokenDetails.policyId.label',
+ defaultMessage: '!!!Policy ID',
+ },
+ fingerprint: {
+ id: 'txReview.tokenDetails.fingerprint.label',
+ defaultMessage: '!!!Fingerprint',
+ },
+ name: {
+ id: 'txReview.tokenDetails.overViewTab.name.label',
+ defaultMessage: '!!!Name',
+ },
+ tokenSupply: {
+ id: 'txReview.tokenDetails.overViewTab.tokenSupply.label',
+ defaultMessage: '!!!Token Supply',
+ },
+ symbol: {
+ id: 'txReview.tokenDetails.overViewTab.symbol.label',
+ defaultMessage: '!!!Symbol',
+ },
+ description: {
+ id: 'txReview.tokenDetails.overViewTab.description.label',
+ defaultMessage: '!!!Description',
+ },
+ details: {
+ id: 'txReview.tokenDetails.overViewTab.details.label',
+ defaultMessage: '!!!Details on',
+ },
+ tokenDetailsTitle: {
+ id: 'txReview.tokenDetails.title',
+ defaultMessage: '!!!Asset Details',
+ },
+})
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useTxBody.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useTxBody.tsx
new file mode 100644
index 0000000000..9de33bb075
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useTxBody.tsx
@@ -0,0 +1,44 @@
+import {useQuery} from 'react-query'
+
+import {wrappedCsl} from '../../../../yoroi-wallets/cardano/wrappedCsl'
+import {YoroiUnsignedTx} from '../../../../yoroi-wallets/types/yoroi'
+
+export const useTxBody = ({cbor, unsignedTx}: {cbor?: string; unsignedTx?: YoroiUnsignedTx}) => {
+ const query = useQuery(
+ ['useTxBody', cbor, unsignedTx],
+ async () => {
+ if (cbor !== undefined) {
+ return getCborTxBody(cbor)
+ } else if (unsignedTx !== undefined) {
+ return getUnsignedTxTxBody(unsignedTx)
+ } else {
+ throw new Error('useTxBody: missing cbor and unsignedTx')
+ }
+ },
+ {
+ useErrorBoundary: true,
+ suspense: true,
+ },
+ )
+
+ if (query.data === undefined) throw new Error('useTxBody: cannot extract txBody')
+ return query.data
+}
+const getCborTxBody = async (cbor: string) => {
+ const {csl, release} = wrappedCsl()
+ try {
+ const tx = await csl.Transaction.fromHex(cbor)
+ const jsonString = await tx.toJson()
+ return JSON.parse(jsonString).body
+ } finally {
+ release()
+ }
+}
+
+const getUnsignedTxTxBody = async (unsignedTx: YoroiUnsignedTx) => {
+ const {
+ unsignedTx: {txBody},
+ } = unsignedTx
+ const txBodyjson = await txBody.toJson()
+ return JSON.parse(txBodyjson)
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/mocks.ts b/apps/wallet-mobile/src/features/ReviewTx/common/mocks.ts
new file mode 100644
index 0000000000..12fbe9274a
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/mocks.ts
@@ -0,0 +1,148 @@
+import {TransactionBody} from './types'
+
+export const adaTransactionSingleReceiver: TransactionBody = {
+ inputs: [
+ {
+ transaction_id: '46fe71d85a733d970fe7bb8e6586624823803936d18c7e14601713d05b5b287a',
+ index: 0,
+ },
+ {
+ transaction_id: '9638640d421875f068d10a0125023601bbd7e83e7f17b721c9c06c97cc29ff66',
+ index: 1,
+ },
+ ],
+ outputs: [
+ {
+ address:
+ 'addr1qyf4x8lvcyrwcxzkyz3lykyzfu7s7x307dlafgsu89qzge8lfl229ahk888cgakug24y86qtduvn065c3gw7dg5002cqdskm74',
+ amount: {
+ coin: '12000000',
+ multiasset: null,
+ },
+ plutus_data: null,
+ script_ref: null,
+ },
+ {
+ address:
+ 'addr1q9xy5p0cz2zsjrzpg4tl59mltjmfh07yc28alchxjlanygk0ppwv8x4ylafdu84xqmh9sx4vrk4czekksv884xmvanwqde82xg',
+ amount: {
+ coin: '23464562',
+ multiasset: null,
+ },
+ plutus_data: null,
+ script_ref: null,
+ },
+ ],
+ fee: '174345',
+ ttl: '220373661',
+ certs: null,
+ withdrawals: null,
+ update: null,
+ auxiliary_data_hash: null,
+ validity_start_interval: null,
+ mint: null,
+ script_data_hash: null,
+ collateral: null,
+ required_signers: null,
+ network_id: null,
+ collateral_return: null,
+ total_collateral: null,
+ reference_inputs: null,
+ voting_procedures: null,
+ voting_proposals: null,
+ donation: null,
+ current_treasury_value: null,
+}
+
+export const multiAssetsTransactionOneReceiver: TransactionBody = {
+ inputs: [
+ {
+ transaction_id: '46fe71d85a733d970fe7bb8e6586624823803936d18c7e14601713d05b5b287a',
+ index: 0,
+ },
+ {
+ transaction_id: 'bddd3e0b43b9b93f6d49190a9d4d55c3cd28e3d270b0f1bbc0f83b8ecc3e373a',
+ index: 1,
+ },
+ ],
+ outputs: [
+ {
+ address:
+ 'addr1qyf4x8lvcyrwcxzkyz3lykyzfu7s7x307dlafgsu89qzge8lfl229ahk888cgakug24y86qtduvn065c3gw7dg5002cqdskm74',
+ amount: {
+ coin: '10000000',
+ multiasset: {
+ cdaaee586376139ee8c3cc4061623968810d177ca5c300afb890b48a: {
+ '43415354': '5',
+ },
+ f0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9a: {
+ '000de1406a6176696275656e6f': '1',
+ },
+ },
+ },
+ plutus_data: null,
+ script_ref: null,
+ },
+ {
+ address:
+ 'addr1q9xy5p0cz2zsjrzpg4tl59mltjmfh07yc28alchxjlanygk0ppwv8x4ylafdu84xqmh9sx4vrk4czekksv884xmvanwqde82xg',
+ amount: {
+ coin: '2228270',
+ multiasset: {
+ '2441ab3351c3b80213a98f4e09ddcf7dabe4879c3c94cc4e7205cb63': {
+ '46495245': '2531',
+ },
+ '279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3f': {
+ '534e454b': '204',
+ },
+ '4cb48d60d1f7823d1307c61b9ecf472ff78cf22d1ccc5786d59461f8': {
+ '4144414d4f4f4e': '4983996',
+ },
+ a0028f350aaabe0545fdcb56b039bfb08e4bb4d8c4d7c3c7d481c235: {
+ '484f534b59': '115930085',
+ },
+ cdaaee586376139ee8c3cc4061623968810d177ca5c300afb890b48a: {
+ '43415354': '4503',
+ },
+ e0c4c2d7c4a0ed2cf786753fd845dee82c45512cee03e92adfd3fb8d: {
+ '6a6176696275656e6f2e616461': '1',
+ },
+ fc411f546d01e88a822200243769bbc1e1fbdde8fa0f6c5179934edb: {
+ '6a6176696275656e6f': '1',
+ },
+ },
+ },
+ plutus_data: null,
+ script_ref: null,
+ },
+ {
+ address:
+ 'addr1q9xy5p0cz2zsjrzpg4tl59mltjmfh07yc28alchxjlanygk0ppwv8x4ylafdu84xqmh9sx4vrk4czekksv884xmvanwqde82xg',
+ amount: {
+ coin: '2300311',
+ multiasset: null,
+ },
+ plutus_data: null,
+ script_ref: null,
+ },
+ ],
+ fee: '189349',
+ ttl: '93045',
+ certs: null,
+ withdrawals: null,
+ update: null,
+ auxiliary_data_hash: null,
+ validity_start_interval: null,
+ mint: null,
+ script_data_hash: null,
+ collateral: null,
+ required_signers: null,
+ network_id: null,
+ collateral_return: null,
+ total_collateral: null,
+ reference_inputs: null,
+ voting_procedures: null,
+ voting_proposals: null,
+ donation: null,
+ current_treasury_value: null,
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/types.ts b/apps/wallet-mobile/src/features/ReviewTx/common/types.ts
new file mode 100644
index 0000000000..45744a4cf6
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/common/types.ts
@@ -0,0 +1,56 @@
+import {
+ TransactionBodyJSON,
+ TransactionInputsJSON,
+ TransactionOutputsJSON,
+} from '@emurgo/cardano-serialization-lib-nodejs'
+import {Balance, Portfolio} from '@yoroi/types'
+
+export type TransactionBody = TransactionBodyJSON
+export type TransactionInputs = TransactionInputsJSON
+export type TransactionOutputs = TransactionOutputsJSON
+
+export type FormattedInput = {
+ assets: Array<{
+ tokenInfo: Portfolio.Token.Info
+ name: string
+ label: string
+ quantity: Balance.Quantity
+ isPrimary: boolean
+ }>
+ address: string | undefined
+ rewardAddress: string | null
+ ownAddress: boolean
+ txIndex: number
+ txHash: string
+}
+
+export type FormattedInputs = Array
+
+export type FormattedOutput = {
+ assets: Array<{
+ tokenInfo: Portfolio.Token.Info
+ name: string
+ label: string
+ quantity: Balance.Quantity
+ isPrimary: boolean
+ }>
+ address: string
+ rewardAddress: string | null
+ ownAddress: boolean
+}
+
+export type FormattedOutputs = Array
+
+export type FormattedFee = {
+ tokenInfo: Portfolio.Token.Info
+ name: string
+ label: string
+ quantity: Balance.Quantity
+ isPrimary: boolean
+}
+
+export type FormattedTx = {
+ inputs: FormattedInputs
+ outputs: FormattedOutputs
+ fee: FormattedFee
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx
new file mode 100644
index 0000000000..92278d03ba
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx
@@ -0,0 +1,396 @@
+// 🚧 TODO: grouping by staking address 🚧
+
+import {Blockies} from '@yoroi/identicon'
+import {useTheme} from '@yoroi/theme'
+import * as React from 'react'
+import {Linking, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
+
+import {Icon} from '../../../../../components/Icon'
+import {Space} from '../../../../../components/Space/Space'
+import {formatTokenWithText} from '../../../../../yoroi-wallets/utils/format'
+import {Quantities} from '../../../../../yoroi-wallets/utils/utils'
+import {useSelectedWallet} from '../../../../WalletManager/common/hooks/useSelectedWallet'
+import {useWalletManager} from '../../../../WalletManager/context/WalletManagerProvider'
+import {Accordion} from '../../../common/Accordion'
+import {CopiableText} from '../../../common/CopiableText'
+import {Divider} from '../../../common/Divider'
+import {useAddressType} from '../../../common/hooks/useAddressType'
+import {useStrings} from '../../../common/hooks/useStrings'
+import {ReviewTxState} from '../../../common/ReviewTxProvider'
+import {TokenItem} from '../../../common/TokenItem'
+import {FormattedOutputs, FormattedTx} from '../../../common/types'
+
+export const OverviewTab = ({tx, operations}: {tx: FormattedTx; operations: ReviewTxState['operations']}) => {
+ const {styles} = useStyles()
+
+ const notOwnedOutputs = React.useMemo(() => tx.outputs.filter((output) => !output.ownAddress), [tx.outputs])
+ const ownedOutputs = React.useMemo(() => tx.outputs.filter((output) => output.ownAddress), [tx.outputs])
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+const WalletInfoSection = ({tx}: {tx: FormattedTx}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+ const {wallet, meta} = useSelectedWallet()
+ const {walletManager} = useWalletManager()
+ const {plate, seed} = walletManager.checksum(wallet.publicKeyHex)
+ const seedImage = new Blockies({seed}).asBase64()
+
+ return (
+ <>
+
+ {strings.walletLabel}
+
+
+
+
+
+
+ {`${plate} | ${meta.name}`}
+
+
+
+
+
+
+ >
+ )
+}
+
+const FeeInfoItem = ({fee}: {fee: string}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ return (
+
+ {strings.feeLabel}
+
+ {`-${fee}`}
+
+ )
+}
+
+const SenderSection = ({
+ tx,
+ notOwnedOutputs,
+ ownedOutputs,
+}: {
+ tx: FormattedTx
+ notOwnedOutputs: FormattedOutputs
+ ownedOutputs: FormattedOutputs
+}) => {
+ const strings = useStrings()
+ const {styles} = useStyles()
+ const address = ownedOutputs[0]?.rewardAddress ?? ownedOutputs[0]?.address
+
+ return (
+
+
+
+
+
+ {address}
+
+
+
+
+
+
+
+ {notOwnedOutputs.length === 1 && }
+
+ )
+}
+
+// 🚧 TODO: ADD MULTIRECEIVER SUPPORT 🚧
+const SenderTokens = ({tx, notOwnedOutputs}: {tx: FormattedTx; notOwnedOutputs: FormattedOutputs}) => {
+ const {styles} = useStyles()
+
+ const {wallet} = useSelectedWallet()
+
+ const totalPrimaryTokenSent = React.useMemo(
+ () =>
+ notOwnedOutputs
+ .flatMap((output) => output.assets.filter((asset) => asset.isPrimary))
+ .reduce((previous, current) => Quantities.sum([previous, current.quantity]), Quantities.zero),
+ [notOwnedOutputs],
+ )
+ const totalPrimaryTokenSpent = React.useMemo(
+ () => Quantities.sum([totalPrimaryTokenSent, tx.fee.quantity]),
+ [totalPrimaryTokenSent, tx.fee.quantity],
+ )
+ const totalPrimaryTokenSpentLabel = formatTokenWithText(totalPrimaryTokenSpent, wallet.portfolioPrimaryTokenInfo)
+
+ const notPrimaryTokenSent = React.useMemo(
+ () => notOwnedOutputs.flatMap((output) => output.assets.filter((asset) => !asset.isPrimary)),
+ [notOwnedOutputs],
+ )
+
+ return (
+
+
+
+
+
+
+
+
+ {notPrimaryTokenSent.map((token, index) => (
+
+ ))}
+
+
+ )
+}
+
+const SenderSectionLabel = () => {
+ const {styles, colors} = useStyles()
+ const strings = useStrings()
+
+ return (
+
+
+
+
+
+ {strings.sendLabel}
+
+ )
+}
+
+const ReceiverSection = ({notOwnedOutputs}: {notOwnedOutputs: FormattedOutputs}) => {
+ const address = notOwnedOutputs[0]?.rewardAddress ?? notOwnedOutputs[0]?.address
+ const {styles} = useStyles()
+ const strings = useStrings()
+ const addressType = useAddressType(address)
+ const isScriptAddress = addressType === 'script'
+
+ return (
+ <>
+
+
+
+ {isScriptAddress ? strings.receiveToScriptLabel : strings.receiveToLabel}:
+
+
+
+ {address}
+
+
+
+ >
+ )
+}
+
+const OperationsSection = ({operations}: {operations: ReviewTxState['operations']}) => {
+ if (operations === null || (Array.isArray(operations) && operations.length === 0)) return null
+
+ return (
+
+
+
+
+
+
+ {operations.map((operation, index) => {
+ if (index === 0) return operation
+
+ return (
+ <>
+
+
+ {operation}
+ >
+ )
+ })}
+
+
+ )
+}
+
+const useStyles = () => {
+ const {atoms, color} = useTheme()
+ const styles = StyleSheet.create({
+ root: {
+ ...atoms.flex_1,
+ ...atoms.px_lg,
+ backgroundColor: color.bg_color_max,
+ },
+ infoItem: {
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ },
+ infoLabel: {
+ ...atoms.body_2_md_regular,
+ color: color.gray_600,
+ },
+ walletInfoText: {
+ ...atoms.body_2_md_medium,
+ color: color.text_primary_medium,
+ },
+ plate: {
+ ...atoms.flex_row,
+ ...atoms.align_center,
+ },
+ fee: {
+ color: color.gray_900,
+ ...atoms.body_2_md_regular,
+ },
+ link: {
+ color: color.text_primary_medium,
+ ...atoms.body_2_md_medium,
+ },
+ receiverAddress: {
+ ...atoms.flex_row,
+ ...atoms.align_center,
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ },
+ tokenSectionLabel: {
+ ...atoms.body_2_md_regular,
+ color: color.gray_900,
+ },
+ senderTokenItems: {
+ ...atoms.flex_wrap,
+ ...atoms.flex_row,
+ ...atoms.justify_end,
+ ...atoms.flex_1,
+ ...atoms.gap_sm,
+ },
+ tokensSection: {
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ },
+ tokensSectionLabel: {
+ ...atoms.flex_row,
+ ...atoms.align_center,
+ },
+ walletChecksum: {
+ width: 24,
+ height: 24,
+ },
+ receiverSectionAddress: {
+ maxWidth: 260,
+ },
+ addressText: {
+ ...atoms.flex_1,
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_medium,
+ },
+ })
+
+ const colors = {
+ send: color.primary_500,
+ received: color.green_static,
+ }
+
+ return {styles, colors} as const
+}
+
+// 🚧 WORK IN PROGRESS BELOW 🚧
+
+// 🚧 TODO: WIP 🚧
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const CreatedByInfoItem = () => {
+ const {styles} = useStyles()
+
+ return (
+
+ Created By
+
+
+ {/* */}
+
+
+
+ Linking.openURL('https://google.com')}>
+ dapp.org
+
+
+
+ )
+}
+
+// 🚧 TODO: WIP 🚧
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+/* const ReceiverTokensSectionMultiReceiver = () => {
+ const {styles} = useStyles()
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+} */
+
+// 🚧 TODO: WIP 🚧
+/* const ReceiverSectionLabel = () => {
+ const {styles, colors} = useStyles()
+
+ return (
+
+
+
+
+
+ Receive
+
+ )
+} */
diff --git a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx
new file mode 100644
index 0000000000..c1d728dbe5
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx
@@ -0,0 +1,158 @@
+import {createMaterialTopTabNavigator, MaterialTopTabBarProps} from '@react-navigation/material-top-tabs'
+import {useTheme} from '@yoroi/theme'
+import * as React from 'react'
+import {FlatList, ScrollView, StyleSheet, Text, TouchableOpacity, TouchableOpacityProps, View} from 'react-native'
+
+import {Button} from '../../../../components/Button/Button'
+import {SafeArea} from '../../../../components/SafeArea'
+import {useFormattedTx} from '../../common/hooks/useFormattedTx'
+import {useOnConfirm} from '../../common/hooks/useOnConfirm'
+import {useStrings} from '../../common/hooks/useStrings'
+import {useTxBody} from '../../common/hooks/useTxBody'
+import {useReviewTx} from '../../common/ReviewTxProvider'
+import {OverviewTab} from './Overview/OverviewTab'
+import {UTxOsTab} from './UTxOs/UTxOsTab'
+
+const MaterialTab = createMaterialTopTabNavigator()
+
+export const ReviewTxScreen = () => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+ const {unsignedTx, operations, onSuccess, onError} = useReviewTx()
+
+ if (unsignedTx === null) throw new Error('ReviewTxScreen: missing unsignedTx')
+
+ const {onConfirm} = useOnConfirm({
+ unsignedTx,
+ onSuccess,
+ onError,
+ })
+
+ // TODO: add cbor arguments
+ const txBody = useTxBody({unsignedTx})
+ const formatedTx = useFormattedTx(txBody)
+
+ const OverViewTabMemo = React.memo(() => )
+ const UTxOsTabMemo = React.memo(() => )
+
+ return (
+
+
+
+ {() => (
+ /* TODO: make scrollview general to use button border */
+
+
+
+ )}
+
+
+
+ {() => (
+ /* TODO: make scrollview general to use button border */
+
+
+
+ )}
+
+
+
+
+
+
+
+ )
+}
+
+const TabBar = ({navigation, state}: MaterialTopTabBarProps) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ return (
+ (
+ navigation.navigate(key)} />
+ )}
+ style={styles.tabBar}
+ showsHorizontalScrollIndicator={false}
+ bounces={false}
+ horizontal
+ />
+ )
+}
+
+export const Tab = ({
+ onPress,
+ active,
+ label,
+ testID,
+ style,
+}: TouchableOpacityProps & {active: boolean; label: string}) => {
+ const {styles} = useStyles()
+
+ return (
+
+
+ {label}
+
+
+ {active && }
+
+ )
+}
+
+const Actions = ({children}: {children: React.ReactNode}) => {
+ const {styles} = useStyles()
+ return {children}
+}
+
+const useStyles = () => {
+ const {atoms, color} = useTheme()
+ const styles = StyleSheet.create({
+ root: {
+ ...atoms.flex_1,
+ backgroundColor: color.bg_color_max,
+ },
+ actions: {
+ ...atoms.p_lg,
+ },
+ tabBar: {
+ marginHorizontal: 16, // to include the border
+ maxHeight: 50,
+ borderBottomWidth: 1,
+ borderBottomColor: color.gray_200,
+ },
+ tab: {
+ ...atoms.align_center,
+ ...atoms.justify_center,
+ ...atoms.py_md,
+ },
+ tabContainer: {
+ ...atoms.align_center,
+ ...atoms.justify_center,
+ ...atoms.px_lg,
+ },
+ tabText: {
+ ...atoms.body_1_lg_medium,
+ },
+ tabTextActive: {
+ color: color.primary_600,
+ },
+ tabTextInactive: {
+ color: color.gray_600,
+ },
+ indicator: {
+ ...atoms.absolute,
+ bottom: 0,
+ height: 2,
+ width: '100%',
+ backgroundColor: color.primary_500,
+ },
+ })
+
+ return {styles} as const
+}
diff --git a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/UTxOs/UTxOsTab.tsx b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/UTxOs/UTxOsTab.tsx
new file mode 100644
index 0000000000..83861af94f
--- /dev/null
+++ b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/UTxOs/UTxOsTab.tsx
@@ -0,0 +1,211 @@
+import {useTheme} from '@yoroi/theme'
+import * as React from 'react'
+import {StyleSheet, Text, View} from 'react-native'
+
+import {Space} from '../../../../../components/Space/Space'
+import {Accordion} from '../../../common/Accordion'
+import {CopiableText} from '../../../common/CopiableText'
+import {Divider} from '../../../common/Divider'
+import {useStrings} from '../../../common/hooks/useStrings'
+import {TokenItem} from '../../../common/TokenItem'
+import {FormattedInput, FormattedInputs, FormattedOutput, FormattedOutputs, FormattedTx} from '../../../common/types'
+
+export const UTxOsTab = ({tx}: {tx: FormattedTx}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+const Inputs = ({inputs}: {inputs: FormattedInputs}) => {
+ return inputs.map((input, index) => )
+}
+
+const Input = ({input}: {input: FormattedInput}) => {
+ const {styles} = useStyles()
+ if (input?.address === undefined) throw new Error('UTxOsTab: input invalid address')
+
+ return (
+
+
+
+
+
+
+
+
+
+ {input.address}
+
+
+
+
+
+ {input.txHash}
+
+
+
+ {`#${input.txIndex}`}
+
+
+
+
+
+
+
+
+ {input.assets.map((asset, index) => (
+
+ ))}
+
+
+ )
+}
+const Outputs = ({outputs}: {outputs: FormattedOutputs}) => {
+ return outputs.map((output, index) => )
+}
+
+const Output = ({output}: {output: FormattedOutput}) => {
+ const {styles} = useStyles()
+ if (output?.address === undefined) throw new Error('UTxOsTab: input invalid address')
+
+ return (
+
+
+
+
+
+
+
+
+
+ {output.address}
+
+
+
+
+
+
+ {output.assets.map((asset, index) => (
+
+ ))}
+
+
+ )
+}
+
+const Fee = ({fee}: {fee: string}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ return (
+
+
+
+
+ {strings.feeLabel}
+
+ {`-${fee}`}
+
+
+
+
+ )
+}
+
+const UtxoTitle = ({isInput, isOwnAdddress}: {isOwnAdddress: boolean; isInput: boolean}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ const label = isOwnAdddress ? strings.utxosYourAddressLabel : strings.utxosForeignAddressLabel
+
+ return (
+
+
+
+
+
+ {label}
+
+ )
+}
+
+const useStyles = () => {
+ const {atoms, color} = useTheme()
+ const styles = StyleSheet.create({
+ root: {
+ ...atoms.flex_1,
+ ...atoms.px_lg,
+ backgroundColor: color.bg_color_max,
+ },
+ utxoTitle: {
+ ...atoms.flex_row,
+ ...atoms.align_center,
+ },
+ utxoTitleCircleInput: {
+ width: 12,
+ height: 12,
+ backgroundColor: color.primary_500,
+ ...atoms.rounded_full,
+ },
+ utxoTitleCircleOutput: {
+ width: 12,
+ height: 12,
+ backgroundColor: color.green_static,
+ ...atoms.rounded_full,
+ },
+ utxoTitleText: {
+ ...atoms.body_2_md_medium,
+ color: color.text_gray_medium,
+ },
+ tokenItems: {
+ ...atoms.flex_row,
+ ...atoms.justify_end,
+ ...atoms.flex_wrap,
+ ...atoms.gap_sm,
+ },
+ fee: {
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ },
+ feeLabel: {
+ ...atoms.body_1_lg_medium,
+ color: color.text_gray_medium,
+ },
+ feeValue: {
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_medium,
+ },
+ addressText: {
+ ...atoms.flex_1,
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_medium,
+ },
+ index: {
+ ...atoms.body_2_md_medium,
+ color: color.text_gray_medium,
+ },
+ })
+
+ return {styles} as const
+}
diff --git a/apps/wallet-mobile/src/features/Send/common/navigation.ts b/apps/wallet-mobile/src/features/Send/common/navigation.ts
index aaf733d819..45a7caedaa 100644
--- a/apps/wallet-mobile/src/features/Send/common/navigation.ts
+++ b/apps/wallet-mobile/src/features/Send/common/navigation.ts
@@ -15,7 +15,6 @@ export const useNavigateTo = () => {
selectedTokens: () => navigation.navigate('send-list-amounts-to-send'),
addToken: () => navigation.navigate('send-select-token-from-list'),
startTx: () => navigation.navigate('send-start-tx'),
- confirmTx: () => navigation.navigate('send-confirm-tx'),
editAmount: () => navigation.navigate('send-edit-amount'),
reader: () => navigation.navigate('scan-start', {insideFeature: 'send'}),
submittedTx: (txId: string) => navigation.navigate('send-submitted-tx', {txId}),
diff --git a/apps/wallet-mobile/src/features/Send/useCases/ConfirmTx/ConfirmTxScreen.stories.tsx b/apps/wallet-mobile/src/features/Send/useCases/ConfirmTx/ConfirmTxScreen.stories.tsx
deleted file mode 100644
index dc5affd9a3..0000000000
--- a/apps/wallet-mobile/src/features/Send/useCases/ConfirmTx/ConfirmTxScreen.stories.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import {storiesOf} from '@storybook/react-native'
-import {TransferProvider} from '@yoroi/transfer'
-import React from 'react'
-
-import {mocks as walletMocks} from '../../../../yoroi-wallets/mocks/wallet'
-import {WalletManagerProviderMock} from '../../../../yoroi-wallets/mocks/WalletManagerProviderMock'
-import {mocks as sendMocks} from '../../common/mocks'
-import {ConfirmTxScreen} from './ConfirmTxScreen'
-
-storiesOf('Confirm Tx', module).add('initial', () => {
- return (
-
-
-
-
-
- )
-})
diff --git a/apps/wallet-mobile/src/features/Send/useCases/ConfirmTx/ConfirmTxScreen.tsx b/apps/wallet-mobile/src/features/Send/useCases/ConfirmTx/ConfirmTxScreen.tsx
deleted file mode 100644
index ca01429bbd..0000000000
--- a/apps/wallet-mobile/src/features/Send/useCases/ConfirmTx/ConfirmTxScreen.tsx
+++ /dev/null
@@ -1,181 +0,0 @@
-import {useFocusEffect} from '@react-navigation/native'
-import {useTheme} from '@yoroi/theme'
-import {useTransfer} from '@yoroi/transfer'
-import React, {useEffect} from 'react'
-import {useIntl} from 'react-intl'
-import {ScrollView, StyleSheet, View, ViewProps} from 'react-native'
-import {SafeAreaView} from 'react-native-safe-area-context'
-
-import {ConfirmTx} from '../../../../components/ConfirmTx/ConfirmTx'
-import {KeyboardAvoidingView} from '../../../../components/KeyboardAvoidingView/KeyboardAvoidingView'
-import {Space} from '../../../../components/Space/Space'
-import {ValidatedTextInput} from '../../../../components/ValidatedTextInput'
-import {isDev} from '../../../../kernel/env'
-import {debugWalletInfo, features} from '../../../../kernel/features'
-import globalMessages, {confirmationMessages, errorMessages, txLabels} from '../../../../kernel/i18n/global-messages'
-import {assetsToSendProperties} from '../../../../kernel/metrics/helpers'
-import {useMetrics} from '../../../../kernel/metrics/metricsManager'
-import {useSaveMemo} from '../../../../yoroi-wallets/hooks'
-import {YoroiSignedTx} from '../../../../yoroi-wallets/types/yoroi'
-import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet'
-import {useNavigateTo} from '../../common/navigation'
-import {useFlashAndScroll} from '../../common/useFlashAndScroll'
-import {BalanceAfter} from './Summary/BalanceAfter'
-import {CurrentBalance} from './Summary/CurrentBalance'
-import {Fees} from './Summary/Fees'
-import {PrimaryTotal} from './Summary/PrimaryTotal'
-import {ReceiverInfo} from './Summary/ReceiverInfo'
-import {SecondaryTotals} from './Summary/SecondaryTotals'
-
-export const ConfirmTxScreen = () => {
- const strings = useStrings()
- const styles = useStyles()
- const {wallet, meta} = useSelectedWallet()
- const navigateTo = useNavigateTo()
- const [password, setPassword] = React.useState('')
- const [useUSB, setUseUSB] = React.useState(false)
- const {track} = useMetrics()
-
- const {memo, selectedTargetIndex, unsignedTx: yoroiUnsignedTx, targets} = useTransfer()
- const {amounts} = targets[selectedTargetIndex].entry
-
- const {saveMemo} = useSaveMemo({wallet})
-
- useEffect(() => {
- if (features.prefillWalletInfo && isDev) {
- setPassword(debugWalletInfo.PASSWORD)
- }
- }, [])
-
- const sendProperties = React.useMemo(() => assetsToSendProperties({amounts}), [amounts])
-
- useFocusEffect(
- React.useCallback(() => {
- track.sendSummaryPageViewed(sendProperties)
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [track]),
- )
-
- const onSuccess = (signedTx: YoroiSignedTx) => {
- track.sendSummarySubmitted(sendProperties)
- navigateTo.submittedTx(signedTx.signedTx.id)
-
- if (memo.length > 0) {
- saveMemo({txId: signedTx.signedTx.id, memo: memo.trim()})
- }
- }
-
- const onError = () => {
- track.sendSummarySubmitted(sendProperties)
- navigateTo.failedTx()
- }
-
- const scrollViewRef = useFlashAndScroll()
-
- if (yoroiUnsignedTx === undefined) throw new Error('Missing yoroiUnsignedTx')
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- {targets.map((target, index) => (
-
- ))}
-
-
-
-
-
-
-
-
-
-
-
- {!meta.isEasyConfirmationEnabled && !meta.isHW && (
-
- )}
-
-
-
-
-
-
-
- )
-}
-
-const Actions = ({style, ...props}: ViewProps) => {
- const styles = useStyles()
- return
-}
-
-const useStyles = () => {
- const {color, atoms} = useTheme()
-
- const styles = StyleSheet.create({
- root: {
- backgroundColor: color.bg_color_max,
- },
- safeAreaView: {
- ...atoms.gap_lg,
- ...atoms.pb_lg,
- },
- scrollView: {
- ...atoms.flex_1,
- ...atoms.px_lg,
- },
- flex: {
- ...atoms.flex_1,
- },
- actions: {
- ...atoms.px_lg,
- },
- })
- return styles
-}
-
-const useStrings = () => {
- const intl = useIntl()
-
- return {
- availableFunds: intl.formatMessage(globalMessages.availableFunds),
- balanceAfterTx: intl.formatMessage(txLabels.balanceAfterTx),
- total: intl.formatMessage(globalMessages.total),
- password: intl.formatMessage(txLabels.password),
- confirmButton: intl.formatMessage(confirmationMessages.commonButtons.confirmButton),
- submittingTx: intl.formatMessage(txLabels.submittingTx),
- pleaseWait: intl.formatMessage(globalMessages.pleaseWait),
- generalTxError: {
- title: intl.formatMessage(errorMessages.generalTxError.title),
- message: intl.formatMessage(errorMessages.generalTxError.message),
- },
- }
-}
diff --git a/apps/wallet-mobile/src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.tsx b/apps/wallet-mobile/src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.tsx
index aebcf4ff06..aa4bfac370 100644
--- a/apps/wallet-mobile/src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.tsx
+++ b/apps/wallet-mobile/src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.tsx
@@ -18,8 +18,11 @@ import {Spacer} from '../../../../components/Spacer/Spacer'
import globalMessages from '../../../../kernel/i18n/global-messages'
import {assetsToSendProperties} from '../../../../kernel/metrics/helpers'
import {useMetrics} from '../../../../kernel/metrics/metricsManager'
-import {YoroiEntry} from '../../../../yoroi-wallets/types/yoroi'
+import {useWalletNavigation} from '../../../../kernel/navigation'
+import {useSaveMemo} from '../../../../yoroi-wallets/hooks'
+import {YoroiEntry, YoroiSignedTx} from '../../../../yoroi-wallets/types/yoroi'
import {TokenAmountItem} from '../../../Portfolio/common/TokenAmountItem/TokenAmountItem'
+import {useReviewTx} from '../../../ReviewTx/common/ReviewTxProvider'
import {useSearch} from '../../../Search/SearchContext'
import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet'
import {useNavigateTo, useOverridePreviousSendTxRoute} from '../../common/navigation'
@@ -30,10 +33,13 @@ import {RemoveAmountButton} from './RemoveAmount'
export const ListAmountsToSendScreen = () => {
const {styles} = useStyles()
const navigateTo = useNavigateTo()
+ const {navigateToTxReview} = useWalletNavigation()
const strings = useStrings()
const {clearSearch} = useSearch()
const navigation = useNavigation()
const {track} = useMetrics()
+ const {wallet} = useSelectedWallet()
+ const {unsignedTxChanged, onSuccessChanged, onErrorChanged} = useReviewTx()
useOverridePreviousSendTxRoute('send-start-tx')
@@ -41,17 +47,11 @@ export const ListAmountsToSendScreen = () => {
navigation.setOptions({headerLeft: () => })
}, [navigation])
- const {
- targets,
- selectedTargetIndex,
- tokenSelectedChanged,
- amountRemoved,
- unsignedTxChanged: yoroiUnsignedTxChanged,
- } = useTransfer()
+ const {memo, targets, selectedTargetIndex, tokenSelectedChanged, amountRemoved} = useTransfer()
+ const {saveMemo} = useSaveMemo({wallet})
const {amounts} = targets[selectedTargetIndex].entry
const selectedTokensCounter = Object.keys(amounts).length
- const {wallet} = useSelectedWallet()
const {
meta: {addressMode},
} = useSelectedWallet()
@@ -80,14 +80,33 @@ export const ListAmountsToSendScreen = () => {
}
amountRemoved(tokenId)
}
+
+ const sendProperties = React.useMemo(() => assetsToSendProperties({amounts}), [amounts])
+
+ const onSuccess = (signedTx: YoroiSignedTx) => {
+ track.sendSummarySubmitted(sendProperties)
+ navigateTo.submittedTx(signedTx.signedTx.id)
+
+ if (memo.length > 0) {
+ saveMemo({txId: signedTx.signedTx.id, memo: memo.trim()})
+ }
+ }
+
+ const onError = () => {
+ track.sendSummarySubmitted(sendProperties)
+ navigateTo.failedTx()
+ }
+
const onNext = () => {
track.sendSelectAssetSelected(assetsToSendProperties({amounts}))
// since the user can't see many targets we just send the first one
// NOTE: update on multi target support
createUnsignedTx([toYoroiEntry(targets[selectedTargetIndex].entry)], {
onSuccess: (yoroiUnsignedTx) => {
- yoroiUnsignedTxChanged(yoroiUnsignedTx)
- navigateTo.confirmTx()
+ unsignedTxChanged(yoroiUnsignedTx)
+ onSuccessChanged(onSuccess)
+ onErrorChanged(onError)
+ navigateToTxReview()
},
})
}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/CollateralInfoModal.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/CollateralInfoModal.tsx
new file mode 100644
index 0000000000..98a14c7025
--- /dev/null
+++ b/apps/wallet-mobile/src/features/Settings/ManageCollateral/CollateralInfoModal.tsx
@@ -0,0 +1,41 @@
+import {useTheme} from '@yoroi/theme'
+import * as React from 'react'
+import {StyleSheet, Text, View} from 'react-native'
+
+import {InfoModalIllustration} from './illustrations/InfoModalIllustration'
+import {useStrings} from './strings'
+
+export const CollateralInfoModal = () => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ return (
+
+
+
+ {strings.collateralInfoModalText}
+
+ )
+}
+
+const useStyles = () => {
+ const {color, atoms} = useTheme()
+ const styles = StyleSheet.create({
+ modal: {
+ ...atoms.flex_1,
+ ...atoms.px_lg,
+ ...atoms.align_center,
+ },
+ modalText: {
+ ...atoms.text_center,
+ ...atoms.body_1_lg_regular,
+ color: color.text_gray_medium,
+ },
+ })
+
+ const colors = {
+ iconColor: color.gray_900,
+ }
+
+ return {styles, colors} as const
+}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/ConfirmTxScreen.stories.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/ConfirmTxScreen.stories.tsx
deleted file mode 100644
index a62d55cffe..0000000000
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/ConfirmTxScreen.stories.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import {storiesOf} from '@storybook/react-native'
-import {TransferProvider} from '@yoroi/transfer'
-import React from 'react'
-
-import {mocks as walletMocks} from '../../../../yoroi-wallets/mocks/wallet'
-import {WalletManagerProviderMock} from '../../../../yoroi-wallets/mocks/WalletManagerProviderMock'
-import {mocks as sendMocks} from '../../../Send/common/mocks'
-import {ConfirmTxScreen} from './ConfirmTxScreen'
-
-storiesOf('Confirm Tx', module).add('initial', () => {
- return (
-
-
-
-
-
- )
-})
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/ConfirmTxScreen.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/ConfirmTxScreen.tsx
deleted file mode 100644
index a81b7b750c..0000000000
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/ConfirmTxScreen.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
-import {useTheme} from '@yoroi/theme'
-import {useTransfer} from '@yoroi/transfer'
-import React, {useEffect} from 'react'
-import {useIntl} from 'react-intl'
-import {ScrollView, StyleSheet, View, ViewProps} from 'react-native'
-import {SafeAreaView} from 'react-native-safe-area-context'
-
-import {ConfirmTx} from '../../../../components/ConfirmTx/ConfirmTx'
-import {KeyboardAvoidingView} from '../../../../components/KeyboardAvoidingView/KeyboardAvoidingView'
-import {Spacer} from '../../../../components/Spacer/Spacer'
-import {ValidatedTextInput} from '../../../../components/ValidatedTextInput'
-import {debugWalletInfo, features} from '../../../../kernel/features'
-import globalMessages, {confirmationMessages, errorMessages, txLabels} from '../../../../kernel/i18n/global-messages'
-import {useSetCollateralId} from '../../../../yoroi-wallets/cardano/utxoManager/useSetCollateralId'
-import {useSaveMemo} from '../../../../yoroi-wallets/hooks'
-import {YoroiSignedTx} from '../../../../yoroi-wallets/types/yoroi'
-import {CurrentBalance} from '../../../Send/useCases/ConfirmTx/Summary/CurrentBalance'
-import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet'
-import {useNavigateTo} from '../navigation'
-import {BalanceAfter} from './Summary/BalanceAfter'
-import {Fees} from './Summary/Fees'
-import {PrimaryTotal} from './Summary/PrimaryTotal'
-import {SecondaryTotals} from './Summary/SecondaryTotals'
-
-export const ConfirmTxScreen = () => {
- const strings = useStrings()
- const styles = useStyles()
- const {wallet, meta} = useSelectedWallet()
- const navigateTo = useNavigateTo()
- const [password, setPassword] = React.useState('')
- const [useUSB, setUseUSB] = React.useState(false)
- const {setCollateralId} = useSetCollateralId(wallet)
-
- const {memo, unsignedTx: yoroiUnsignedTx} = useTransfer()
-
- const {saveMemo} = useSaveMemo({wallet})
-
- useEffect(() => {
- if (features.prefillWalletInfo && __DEV__) {
- setPassword(debugWalletInfo.PASSWORD)
- }
- }, [])
-
- const onSuccess = (signedTx: YoroiSignedTx) => {
- navigateTo.submittedTx()
- const collateralId = `${signedTx.signedTx.id}:0`
- setCollateralId(collateralId)
- if (memo.length > 0) {
- saveMemo({txId: signedTx.signedTx.id, memo: memo.trim()})
- }
- }
-
- const onError = () => {
- navigateTo.failedTx()
- }
-
- if (yoroiUnsignedTx === undefined) throw new Error('Missing yoroiUnsignedTx')
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {!meta.isEasyConfirmationEnabled && !meta.isHW && (
-
- )}
-
-
-
-
-
-
-
- )
-}
-
-const Actions = (props: ViewProps) => {
- const styles = useStyles()
- return
-}
-
-const useStyles = () => {
- const {color} = useTheme()
- const styles = StyleSheet.create({
- root: {
- backgroundColor: color.bg_color_max,
- flex: 1,
- },
- container: {
- flex: 1,
- paddingHorizontal: 16,
- },
- actions: {
- paddingTop: 16,
- paddingHorizontal: 16,
- },
- })
- return styles
-}
-
-const useStrings = () => {
- const intl = useIntl()
-
- return {
- availableFunds: intl.formatMessage(globalMessages.availableFunds),
- balanceAfterTx: intl.formatMessage(txLabels.balanceAfterTx),
- total: intl.formatMessage(globalMessages.total),
- password: intl.formatMessage(txLabels.password),
- confirmButton: intl.formatMessage(confirmationMessages.commonButtons.confirmButton),
- submittingTx: intl.formatMessage(txLabels.submittingTx),
- pleaseWait: intl.formatMessage(globalMessages.pleaseWait),
- generalTxError: {
- title: intl.formatMessage(errorMessages.generalTxError.title),
- message: intl.formatMessage(errorMessages.generalTxError.message),
- },
- }
-}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/BalanceAfter.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/BalanceAfter.tsx
deleted file mode 100644
index 44a25cc607..0000000000
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/BalanceAfter.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import * as React from 'react'
-import {useIntl} from 'react-intl'
-
-import {Text} from '../../../../../components/Text'
-import {txLabels} from '../../../../../kernel/i18n/global-messages'
-import {useBalances} from '../../../../../yoroi-wallets/hooks'
-import {YoroiUnsignedTx} from '../../../../../yoroi-wallets/types/yoroi'
-import {formatTokenWithSymbol} from '../../../../../yoroi-wallets/utils/format'
-import {Amounts} from '../../../../../yoroi-wallets/utils/utils'
-import {useSelectedWallet} from '../../../../WalletManager/common/hooks/useSelectedWallet'
-
-export const BalanceAfter = ({yoroiUnsignedTx}: {yoroiUnsignedTx: YoroiUnsignedTx}) => {
- const strings = useStrings()
- const {wallet} = useSelectedWallet()
- const balances = useBalances(wallet)
-
- const balancesAfter = Amounts.diff(balances, yoroiUnsignedTx.fee)
- const primaryAmountAfter = Amounts.getAmount(balancesAfter, wallet.portfolioPrimaryTokenInfo.id)
-
- return (
-
- {`${strings.balanceAfterTx}: ${formatTokenWithSymbol(
- primaryAmountAfter.quantity,
- wallet.portfolioPrimaryTokenInfo,
- )}`}
-
- )
-}
-
-const useStrings = () => {
- const intl = useIntl()
-
- return {
- balanceAfterTx: intl.formatMessage(txLabels.balanceAfterTx),
- }
-}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/Fees.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/Fees.tsx
deleted file mode 100644
index 05ad1a135f..0000000000
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/Fees.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import * as React from 'react'
-import {useIntl} from 'react-intl'
-
-import {Text} from '../../../../../components/Text'
-import {txLabels} from '../../../../../kernel/i18n/global-messages'
-import {YoroiUnsignedTx} from '../../../../../yoroi-wallets/types/yoroi'
-import {formatTokenWithSymbol} from '../../../../../yoroi-wallets/utils/format'
-import {Amounts} from '../../../../../yoroi-wallets/utils/utils'
-import {useSelectedWallet} from '../../../../WalletManager/common/hooks/useSelectedWallet'
-
-export const Fees = ({yoroiUnsignedTx}: {yoroiUnsignedTx: YoroiUnsignedTx}) => {
- const strings = useStrings()
- const {wallet} = useSelectedWallet()
- const feeAmount = Amounts.getAmount(yoroiUnsignedTx.fee, wallet.portfolioPrimaryTokenInfo.id)
-
- return (
-
- {`${strings.fees}: ${formatTokenWithSymbol(feeAmount.quantity, wallet.portfolioPrimaryTokenInfo)}`}
-
- )
-}
-
-const useStrings = () => {
- const intl = useIntl()
-
- return {
- fees: intl.formatMessage(txLabels.fees),
- }
-}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/PrimaryTotal.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/PrimaryTotal.tsx
deleted file mode 100644
index a34bfdebf5..0000000000
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/PrimaryTotal.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import {useTheme} from '@yoroi/theme'
-import * as React from 'react'
-import {useIntl} from 'react-intl'
-import {StyleSheet, View} from 'react-native'
-
-import {Text} from '../../../../../components/Text'
-import globalMessages from '../../../../../kernel/i18n/global-messages'
-import {YoroiUnsignedTx} from '../../../../../yoroi-wallets/types/yoroi'
-import {formatTokenWithSymbol} from '../../../../../yoroi-wallets/utils/format'
-import {Amounts} from '../../../../../yoroi-wallets/utils/utils'
-import {useSelectedWallet} from '../../../../WalletManager/common/hooks/useSelectedWallet'
-
-export const PrimaryTotal = ({yoroiUnsignedTx}: {yoroiUnsignedTx: YoroiUnsignedTx}) => {
- const strings = useStrings()
- const styles = useStyles()
- const {wallet} = useSelectedWallet()
- const primaryAmount = Amounts.getAmount(
- Amounts.getAmountsFromEntries(yoroiUnsignedTx.entries),
- wallet.portfolioPrimaryTokenInfo.id,
- )
-
- return (
-
- {strings.total}
-
-
- {formatTokenWithSymbol(primaryAmount.quantity, wallet.portfolioPrimaryTokenInfo)}
-
-
- )
-}
-
-const useStrings = () => {
- const intl = useIntl()
-
- return {
- total: intl.formatMessage(globalMessages.total),
- }
-}
-const useStyles = () => {
- const {color} = useTheme()
- const styles = StyleSheet.create({
- amount: {
- color: color.secondary_600,
- },
- })
- return styles
-}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/SecondaryTotals.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/SecondaryTotals.tsx
deleted file mode 100644
index 318160016a..0000000000
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/Summary/SecondaryTotals.tsx
+++ /dev/null
@@ -1,59 +0,0 @@
-import {createUnknownTokenInfo, usePortfolioTokenInfo} from '@yoroi/portfolio'
-import {useTheme} from '@yoroi/theme'
-import {Balance, Portfolio} from '@yoroi/types'
-import * as React from 'react'
-import {StyleSheet, View} from 'react-native'
-
-import {Boundary} from '../../../../../components/Boundary/Boundary'
-import {Text} from '../../../../../components/Text'
-import {YoroiWallet} from '../../../../../yoroi-wallets/cardano/types'
-import {YoroiUnsignedTx} from '../../../../../yoroi-wallets/types/yoroi'
-import {formatTokenWithText} from '../../../../../yoroi-wallets/utils/format'
-import {Amounts, Quantities} from '../../../../../yoroi-wallets/utils/utils'
-import {useSelectedWallet} from '../../../../WalletManager/common/hooks/useSelectedWallet'
-
-export const SecondaryTotals = ({yoroiUnsignedTx}: {yoroiUnsignedTx: YoroiUnsignedTx}) => {
- const {wallet} = useSelectedWallet()
- const secondaryAmounts = Amounts.remove(Amounts.getAmountsFromEntries(yoroiUnsignedTx.entries), [
- wallet.portfolioPrimaryTokenInfo.id,
- ])
- const sortedAmounts = Amounts.toArray(secondaryAmounts).sort((a, b) =>
- Quantities.isGreaterThan(a.quantity, b.quantity) ? -1 : 1,
- )
-
- return (
-
- {sortedAmounts.map((amount) => (
-
-
-
- ))}
-
- )
-}
-
-const Amount = ({amount, wallet}: {amount: Balance.Amount; wallet: YoroiWallet}) => {
- const styles = useStyles()
- const {tokenInfo} = usePortfolioTokenInfo({
- network: wallet.networkManager.network,
- id: amount.tokenId as Portfolio.Token.Id,
- getTokenInfo: wallet.networkManager.tokenManager.api.tokenInfo,
- primaryTokenInfo: wallet.portfolioPrimaryTokenInfo,
- })
-
- const info =
- tokenInfo ??
- createUnknownTokenInfo({id: amount.tokenId as Portfolio.Token.Id, name: `Unknown token ${amount.tokenId}`})
-
- return {formatTokenWithText(amount.quantity, info)}
-}
-
-const useStyles = () => {
- const {color} = useTheme()
- const styles = StyleSheet.create({
- amount: {
- color: color.secondary_600,
- },
- })
- return styles
-}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/index.ts b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/index.ts
deleted file mode 100644
index 8e77dd2083..0000000000
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ConfirmTx/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './ConfirmTxScreen'
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/InitialCollateralInfoModal.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/InitialCollateralInfoModal.tsx
new file mode 100644
index 0000000000..589cd07a1f
--- /dev/null
+++ b/apps/wallet-mobile/src/features/Settings/ManageCollateral/InitialCollateralInfoModal.tsx
@@ -0,0 +1,52 @@
+import {useTheme} from '@yoroi/theme'
+import * as React from 'react'
+import {StyleSheet, Text, View} from 'react-native'
+
+import {Button} from '../../../components/Button/Button'
+import {Space} from '../../../components/Space/Space'
+import {InfoModalIllustration} from './illustrations/InfoModalIllustration'
+import {useStrings} from './strings'
+
+export const InitialCollateralInfoModal = ({onConfirm}: {onConfirm: () => void}) => {
+ const {styles} = useStyles()
+ const strings = useStrings()
+
+ return (
+
+
+
+ {strings.collateralInfoModalText}
+
+
+
+
+
+
+
+ )
+}
+
+const useStyles = () => {
+ const {color, atoms} = useTheme()
+ const styles = StyleSheet.create({
+ modal: {
+ ...atoms.flex_1,
+ ...atoms.px_lg,
+ ...atoms.align_center,
+ },
+ modalText: {
+ ...atoms.text_center,
+ ...atoms.body_1_lg_regular,
+ color: color.text_gray_medium,
+ },
+ actions: {
+ alignSelf: 'stretch',
+ },
+ })
+
+ const colors = {
+ iconColor: color.gray_900,
+ }
+
+ return {styles, colors} as const
+}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ManageCollateralScreen.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ManageCollateralScreen.tsx
index 7f8d2d6c53..2662984730 100644
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/ManageCollateralScreen.tsx
+++ b/apps/wallet-mobile/src/features/Settings/ManageCollateral/ManageCollateralScreen.tsx
@@ -1,6 +1,4 @@
-import {toBigInt} from '@yoroi/common'
import {useTheme} from '@yoroi/theme'
-import {useTransfer} from '@yoroi/transfer'
import {Portfolio} from '@yoroi/types'
import BigNumber from 'bignumber.js'
import * as React from 'react'
@@ -11,6 +9,7 @@ import {
StyleSheet,
TouchableOpacity,
TouchableOpacityProps,
+ useWindowDimensions,
View,
ViewProps,
} from 'react-native'
@@ -21,20 +20,25 @@ import {Button} from '../../../components/Button/Button'
import {CopyButton} from '../../../components/CopyButton'
import {ErrorPanel} from '../../../components/ErrorPanel/ErrorPanel'
import {Icon} from '../../../components/Icon'
+import {Info} from '../../../components/Icon/Info'
+import {useModal} from '../../../components/Modal/ModalContext'
import {Space} from '../../../components/Space/Space'
import {Spacer} from '../../../components/Spacer/Spacer'
import {Text} from '../../../components/Text'
-import {SettingsStackRoutes, useUnsafeParams} from '../../../kernel/navigation'
+import {SettingsStackRoutes, useUnsafeParams, useWalletNavigation} from '../../../kernel/navigation'
import {useCollateralInfo} from '../../../yoroi-wallets/cardano/utxoManager/useCollateralInfo'
import {useSetCollateralId} from '../../../yoroi-wallets/cardano/utxoManager/useSetCollateralId'
import {collateralConfig, utxosMaker} from '../../../yoroi-wallets/cardano/utxoManager/utxos'
import {useBalances} from '../../../yoroi-wallets/hooks'
import {RawUtxo} from '../../../yoroi-wallets/types/other'
-import {YoroiEntry} from '../../../yoroi-wallets/types/yoroi'
+import {YoroiEntry, YoroiSignedTx} from '../../../yoroi-wallets/types/yoroi'
import {Amounts, asQuantity, Quantities} from '../../../yoroi-wallets/utils/utils'
import {TokenAmountItem} from '../../Portfolio/common/TokenAmountItem/TokenAmountItem'
+import {useReviewTx} from '../../ReviewTx/common/ReviewTxProvider'
import {useSelectedWallet} from '../../WalletManager/common/hooks/useSelectedWallet'
+import {CollateralInfoModal} from './CollateralInfoModal'
import {createCollateralEntry} from './helpers'
+import {InitialCollateralInfoModal} from './InitialCollateralInfoModal'
import {useNavigateTo} from './navigation'
import {useStrings} from './strings'
@@ -44,23 +48,20 @@ export const ManageCollateralScreen = () => {
wallet,
meta: {addressMode},
} = useSelectedWallet()
+ const screenHeight = useWindowDimensions().height
const {amount, collateralId, utxo} = useCollateralInfo(wallet)
const hasCollateral = collateralId !== '' && utxo !== undefined
const didSpend = collateralId !== '' && utxo === undefined
const navigateTo = useNavigateTo()
+ const {openModal} = useModal()
const strings = useStrings()
const balances = useBalances(wallet)
+ const {navigateToTxReview} = useWalletNavigation()
+ const {unsignedTxChanged, onSuccessChanged, onErrorChanged, operationsChanged} = useReviewTx()
const lockedAmount = asQuantity(wallet.primaryBreakdown.lockedAsStorageCost.toString())
const params = useUnsafeParams()
- const {
- reset: resetSendState,
- receiverResolveChanged,
- amountChanged,
- tokenSelectedChanged,
- unsignedTxChanged: yoroiUnsignedTxChanged,
- } = useTransfer()
const {mutate: createUnsignedTx, isLoading: isLoadingTx} = useMutation({
mutationFn: (entries: YoroiEntry[]) => wallet.createUnsignedTx({entries, addressMode}),
retry: false,
@@ -76,25 +77,27 @@ export const ManageCollateralScreen = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
setCollateralId(collateralId)
}
- const createCollateralTransaction = () => {
- const address = wallet.externalAddresses[0]
- const amount: Portfolio.Token.Amount = {
- quantity: toBigInt(collateralConfig.minLovelace, wallet.portfolioPrimaryTokenInfo.decimals),
- info: wallet.portfolioPrimaryTokenInfo,
- }
- // populate for confirmation screen
- resetSendState()
- receiverResolveChanged(address)
- tokenSelectedChanged(amount.info.id)
- amountChanged(amount)
+ const onSuccess = (signedTx: YoroiSignedTx) => {
+ navigateTo.submittedTx()
+ const collateralId = `${signedTx.signedTx.id}:0`
+ setCollateralId(collateralId)
+ }
+
+ const onError = () => {
+ navigateTo.failedTx()
+ }
+ const createCollateralTransaction = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
createUnsignedTx([createCollateralEntry(wallet)], {
onSuccess: (yoroiUnsignedTx) => {
- yoroiUnsignedTxChanged(yoroiUnsignedTx)
- navigateTo.confirmTx()
+ unsignedTxChanged(yoroiUnsignedTx)
+ operationsChanged([])
+ onSuccessChanged(onSuccess)
+ onErrorChanged(onError)
+ navigateToTxReview()
},
})
}
@@ -126,6 +129,14 @@ export const ManageCollateralScreen = () => {
createCollateralTransaction()
}
+ const handleCollateralInfoModal = () => {
+ openModal(
+ strings.initialCollateralInfoModalTitle,
+ ,
+ Math.min(screenHeight * 0.9, 650),
+ )
+ }
+
const shouldShowPrimaryButton = !hasCollateral || didSpend
const shouldShowBackButton = !shouldShowPrimaryButton && !!params?.backButton
@@ -171,7 +182,7 @@ export const ManageCollateralScreen = () => {
{shouldShowPrimaryButton && (
@@ -228,27 +239,58 @@ const RemoveAmountButton = ({disabled, ...props}: TouchableOpacityProps) => {
)
}
+const Operation = () => {
+ const {styles, colors} = useStyles()
+ const strings = useStrings()
+ const {openModal} = useModal()
+
+ const handleOnPressInfo = () => {
+ openModal(strings.collateralInfoModalTitle, , 500)
+ }
+
+ return (
+
+ {strings.collateralInfoModalLabel}
+
+
+
+
+
+
+
+ )
+}
+
const useStyles = () => {
- const {color} = useTheme()
+ const {color, atoms} = useTheme()
const styles = StyleSheet.create({
safeAreaView: {
backgroundColor: color.bg_color_max,
- flex: 1,
- paddingHorizontal: 16,
+ ...atoms.flex_1,
+ ...atoms.px_lg,
},
amountItem: {
- flexDirection: 'row',
- justifyContent: 'space-between',
- alignItems: 'center',
+ ...atoms.flex_row,
+ ...atoms.justify_between,
+ ...atoms.align_center,
},
heading: {
- flex: 1,
+ ...atoms.flex_1,
alignSelf: 'center',
},
+ operation: {
+ ...atoms.flex_row,
+ ...atoms.align_center,
+ },
+ operationText: {
+ ...atoms.body_2_md_regular,
+ color: color.text_gray_medium,
+ },
})
+
const colors = {
- iconColor: color.gray_max,
+ iconColor: color.gray_900,
}
- return {styles, colors}
+ return {styles, colors} as const
}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/illustrations/InfoModalIllustration.tsx b/apps/wallet-mobile/src/features/Settings/ManageCollateral/illustrations/InfoModalIllustration.tsx
new file mode 100644
index 0000000000..57462d9ee8
--- /dev/null
+++ b/apps/wallet-mobile/src/features/Settings/ManageCollateral/illustrations/InfoModalIllustration.tsx
@@ -0,0 +1,430 @@
+import * as React from 'react'
+import Svg, {Defs, LinearGradient, Path, Stop} from 'react-native-svg'
+
+export const InfoModalIllustration = () => {
+ return (
+
+ )
+}
diff --git a/apps/wallet-mobile/src/features/Settings/ManageCollateral/strings.ts b/apps/wallet-mobile/src/features/Settings/ManageCollateral/strings.ts
index 5a973c8fdf..0b5fc162c0 100644
--- a/apps/wallet-mobile/src/features/Settings/ManageCollateral/strings.ts
+++ b/apps/wallet-mobile/src/features/Settings/ManageCollateral/strings.ts
@@ -10,6 +10,12 @@ export const useStrings = () => {
notEnoughFundsAlertTitle: intl.formatMessage(messages.notEnoughFundsAlertTitle),
notEnoughFundsAlertMessage: intl.formatMessage(messages.notEnoughFundsAlertMessage),
notEnoughFundsAlertOK: intl.formatMessage(messages.notEnoughFundsAlertOK),
+ collateralInfoModalLabel: intl.formatMessage(messages.collateralInfoModalLabel),
+ collateralInfoModalTitle: intl.formatMessage(messages.collateralInfoModalTitle),
+ collateralInfoModalText: intl.formatMessage(messages.collateralInfoModalText),
+ initialCollateralInfoModalTitle: intl.formatMessage(messages.initialCollateralInfoModalTitle),
+ initialCollateralInfoModalText: intl.formatMessage(messages.initialCollateralInfoModalText),
+ initialCollateralInfoModalButton: intl.formatMessage(messages.initialCollateralInfoModalButton),
}
}
@@ -42,4 +48,30 @@ const messages = defineMessages({
id: 'components.settings.collateral.notEnoughFundsAlertOK',
defaultMessage: '!!!OK',
},
+ collateralInfoModalLabel: {
+ id: 'components.settings.collateral.collateralInfoModalLabel',
+ defaultMessage: '!!!Collateral creation',
+ },
+ collateralInfoModalTitle: {
+ id: 'components.settings.collateral.collateralInfoModalTitle',
+ defaultMessage: '!!!What is collateral?',
+ },
+ collateralInfoModalText: {
+ id: 'components.settings.collateral.collateralInfoModalText',
+ defaultMessage:
+ '!!!The collateral mechanism is an important feature that has been designed to ensure successful smart contract execution. It is used to guarantee that Cardano nodes are compensated for their work in case phase-2 validation fails.',
+ },
+ initialCollateralInfoModalTitle: {
+ id: 'components.settings.collateral.initialCollateralInfoModalTitle',
+ defaultMessage: '!!!Collateral creation',
+ },
+ initialCollateralInfoModalText: {
+ id: 'components.settings.collateral.initialCollateralInfoModalText',
+ defaultMessage:
+ '!!!The collateral mechanism is designed to ensure smart contracts on Cardano execute successfully. It guarantees that nodes are compensated for their work if a contract fails during validation.',
+ },
+ initialCollateralInfoModalButton: {
+ id: 'components.settings.collateral.initialCollateralInfoModalButton',
+ defaultMessage: '!!!Add collateral',
+ },
})
diff --git a/apps/wallet-mobile/src/features/Settings/SettingsScreenNavigator.tsx b/apps/wallet-mobile/src/features/Settings/SettingsScreenNavigator.tsx
index 6054fdd899..c624d71cda 100644
--- a/apps/wallet-mobile/src/features/Settings/SettingsScreenNavigator.tsx
+++ b/apps/wallet-mobile/src/features/Settings/SettingsScreenNavigator.tsx
@@ -30,7 +30,6 @@ import {ChangeCurrencyScreen} from './Currency/ChangeCurrencyScreen'
import {DisableEasyConfirmationScreen, EnableEasyConfirmationScreen} from './EasyConfirmation'
import {EnableLoginWithOsScreen} from './EnableLoginWithOs'
import {ManageCollateralScreen} from './ManageCollateral'
-import {ConfirmTxScreen} from './ManageCollateral/ConfirmTx'
import {FailedTxScreen} from './ManageCollateral/ConfirmTx/FailedTx/FailedTxScreen'
import {SubmittedTxScreen} from './ManageCollateral/ConfirmTx/SubmittedTx/SubmittedTxScreen'
import {PrivacyPolicyScreen} from './PrivacyPolicy'
@@ -187,14 +186,6 @@ export const SettingsScreenNavigator = () => {
component={ManageCollateralScreen}
/>
-
-
{
)}
-
-
- 'nft-details-routes': NavigatorScreenParams
+ 'review-tx-routes': NavigatorScreenParams
settings: NavigatorScreenParams
'voting-registration': NavigatorScreenParams
'toggle-analytics-settings': NavigatorScreenParams
@@ -153,7 +153,6 @@ export type TxHistoryRoutes = {
'receive-specific-amount': undefined
'receive-multiple': undefined
'send-start-tx': undefined
- 'send-confirm-tx': undefined
'send-submitted-tx': {txId: string}
'send-failed-tx': undefined
'send-list-amounts-to-send': undefined
@@ -294,6 +293,15 @@ export type PortfolioRoutes = {
history: NavigatorScreenParams
}
+export type ReviewTxRoutes = {
+ 'review-tx': undefined
+}
+
+export type PortfolioTokenListTabRoutes = {
+ 'wallet-token': undefined
+ 'dapps-token': undefined
+}
+
export type VotingRegistrationRoutes = {
'download-catalyst': undefined
'display-pin': undefined
@@ -450,6 +458,15 @@ export const useWalletNavigation = () => {
})
},
+ navigateToTxReview: () => {
+ navigation.navigate('manage-wallets', {
+ screen: 'review-tx-routes',
+ params: {
+ screen: 'review-tx',
+ },
+ })
+ },
+
resetToWalletSetupInit: () => {
navigation.reset({
index: 0,
diff --git a/apps/wallet-mobile/src/yoroi-wallets/cardano/utils.ts b/apps/wallet-mobile/src/yoroi-wallets/cardano/utils.ts
index 2dc0600e65..226323f31c 100644
--- a/apps/wallet-mobile/src/yoroi-wallets/cardano/utils.ts
+++ b/apps/wallet-mobile/src/yoroi-wallets/cardano/utils.ts
@@ -31,6 +31,47 @@ export const deriveRewardAddressHex = async (
return result
}
+export const getAddressType = async (address: string) => {
+ const isKeyAddress = await getIsAddressKeyBech32Format(address)
+ if (isKeyAddress) return 'key'
+
+ const isScriptAddress = await getIsAddressScriptBech32Format(address)
+ if (isScriptAddress) return 'script'
+
+ const isRewardAddress = await getIsRewardAddressBech32Format(address)
+ if (isRewardAddress) return 'reward'
+
+ throw new Error('invalid address format')
+}
+
+const getIsAddressKeyBech32Format = async (address: string): Promise => {
+ try {
+ await CardanoMobile.Ed25519KeyHash.fromBech32(address)
+ return true
+ } catch {
+ return false
+ }
+}
+
+const getIsAddressScriptBech32Format = async (address: string): Promise => {
+ try {
+ await CardanoMobile.ScriptHash.fromBech32(address)
+ return true
+ } catch {
+ return false
+ }
+}
+
+const getIsRewardAddressBech32Format = async (addressBech32: string): Promise => {
+ try {
+ const address = await CardanoMobile.Address.fromBech32(addressBech32)
+ await CardanoMobile.RewardAddress.fromAddress(address)
+ return true
+ } catch {
+ return false
+ }
+}
+
/**
* Multi-asset related
*/
diff --git a/apps/wallet-mobile/translations/messages/src/WalletNavigator.json b/apps/wallet-mobile/translations/messages/src/WalletNavigator.json
index 6e8179e2ac..ce9df7a0e8 100644
--- a/apps/wallet-mobile/translations/messages/src/WalletNavigator.json
+++ b/apps/wallet-mobile/translations/messages/src/WalletNavigator.json
@@ -4,14 +4,14 @@
"defaultMessage": "!!!Transactions",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 303,
+ "line": 306,
"column": 22,
- "index": 10476
+ "index": 10668
},
"end": {
- "line": 306,
+ "line": 309,
"column": 3,
- "index": 10579
+ "index": 10771
}
},
{
@@ -19,14 +19,14 @@
"defaultMessage": "!!!Send",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 307,
+ "line": 310,
"column": 14,
- "index": 10595
+ "index": 10787
},
"end": {
- "line": 310,
+ "line": 313,
"column": 3,
- "index": 10694
+ "index": 10886
}
},
{
@@ -34,14 +34,14 @@
"defaultMessage": "!!!Receive",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 311,
+ "line": 314,
"column": 17,
- "index": 10713
+ "index": 10905
},
"end": {
- "line": 314,
+ "line": 317,
"column": 3,
- "index": 10818
+ "index": 11010
}
},
{
@@ -49,14 +49,14 @@
"defaultMessage": "!!!Dashboard",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 315,
+ "line": 318,
"column": 19,
- "index": 10839
+ "index": 11031
},
"end": {
- "line": 318,
+ "line": 321,
"column": 3,
- "index": 10936
+ "index": 11128
}
},
{
@@ -64,14 +64,14 @@
"defaultMessage": "!!!Delegate",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 319,
+ "line": 322,
"column": 18,
- "index": 10956
+ "index": 11148
},
"end": {
- "line": 322,
+ "line": 325,
"column": 3,
- "index": 11051
+ "index": 11243
}
},
{
@@ -79,14 +79,14 @@
"defaultMessage": "!!!Wallet",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 323,
+ "line": 326,
"column": 16,
- "index": 11069
+ "index": 11261
},
"end": {
- "line": 326,
+ "line": 329,
"column": 3,
- "index": 11167
+ "index": 11359
}
},
{
@@ -94,14 +94,14 @@
"defaultMessage": "!!!Staking",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 327,
+ "line": 330,
"column": 17,
- "index": 11186
+ "index": 11378
},
"end": {
- "line": 330,
+ "line": 333,
"column": 3,
- "index": 11251
+ "index": 11443
}
},
{
@@ -109,14 +109,14 @@
"defaultMessage": "!!!NFT Gallery",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 331,
+ "line": 334,
"column": 14,
- "index": 11267
+ "index": 11459
},
"end": {
- "line": 334,
+ "line": 337,
"column": 3,
- "index": 11361
+ "index": 11553
}
},
{
@@ -124,14 +124,14 @@
"defaultMessage": "!!!Menu",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 335,
+ "line": 338,
"column": 14,
- "index": 11377
+ "index": 11569
},
"end": {
- "line": 338,
+ "line": 341,
"column": 3,
- "index": 11429
+ "index": 11621
}
},
{
@@ -139,14 +139,14 @@
"defaultMessage": "!!!Discover",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 339,
+ "line": 342,
"column": 18,
- "index": 11449
+ "index": 11641
},
"end": {
- "line": 342,
+ "line": 345,
"column": 3,
- "index": 11538
+ "index": 11730
}
},
{
@@ -154,14 +154,14 @@
"defaultMessage": "!!!My wallets",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 343,
+ "line": 346,
"column": 31,
- "index": 11571
+ "index": 11763
},
"end": {
- "line": 346,
+ "line": 349,
"column": 3,
- "index": 11680
+ "index": 11872
}
},
{
@@ -169,14 +169,14 @@
"defaultMessage": "!!!Portfolio",
"file": "src/WalletNavigator.tsx",
"start": {
- "line": 347,
+ "line": 350,
"column": 19,
- "index": 11701
+ "index": 11893
},
"end": {
- "line": 350,
+ "line": 353,
"column": 3,
- "index": 11770
+ "index": 11962
}
}
]
\ No newline at end of file
diff --git a/apps/wallet-mobile/translations/messages/src/features/Portfolio/common/MediaDetailsScreen/MediaDetailsScreen.json b/apps/wallet-mobile/translations/messages/src/features/Portfolio/common/MediaDetailsScreen/MediaDetailsScreen.json
index 3938849601..38ab260df5 100644
--- a/apps/wallet-mobile/translations/messages/src/features/Portfolio/common/MediaDetailsScreen/MediaDetailsScreen.json
+++ b/apps/wallet-mobile/translations/messages/src/features/Portfolio/common/MediaDetailsScreen/MediaDetailsScreen.json
@@ -6,12 +6,12 @@
"start": {
"line": 378,
"column": 9,
- "index": 10888
+ "index": 10908
},
"end": {
"line": 381,
"column": 3,
- "index": 10959
+ "index": 10979
}
},
{
@@ -21,12 +21,12 @@
"start": {
"line": 382,
"column": 12,
- "index": 10973
+ "index": 10993
},
"end": {
"line": 385,
"column": 3,
- "index": 11044
+ "index": 11064
}
},
{
@@ -36,12 +36,12 @@
"start": {
"line": 386,
"column": 12,
- "index": 11058
+ "index": 11078
},
"end": {
"line": 389,
"column": 3,
- "index": 11129
+ "index": 11149
}
},
{
@@ -51,12 +51,12 @@
"start": {
"line": 390,
"column": 11,
- "index": 11142
+ "index": 11162
},
"end": {
"line": 393,
"column": 3,
- "index": 11212
+ "index": 11232
}
},
{
@@ -66,12 +66,12 @@
"start": {
"line": 394,
"column": 13,
- "index": 11227
+ "index": 11247
},
"end": {
"line": 397,
"column": 3,
- "index": 11298
+ "index": 11318
}
},
{
@@ -81,12 +81,12 @@
"start": {
"line": 398,
"column": 15,
- "index": 11315
+ "index": 11335
},
"end": {
"line": 401,
"column": 3,
- "index": 11392
+ "index": 11412
}
},
{
@@ -96,12 +96,12 @@
"start": {
"line": 402,
"column": 10,
- "index": 11404
+ "index": 11424
},
"end": {
"line": 405,
"column": 3,
- "index": 11471
+ "index": 11491
}
},
{
@@ -111,12 +111,12 @@
"start": {
"line": 406,
"column": 15,
- "index": 11488
+ "index": 11508
},
"end": {
"line": 409,
"column": 3,
- "index": 11565
+ "index": 11585
}
},
{
@@ -126,12 +126,12 @@
"start": {
"line": 410,
"column": 12,
- "index": 11579
+ "index": 11599
},
"end": {
"line": 413,
"column": 3,
- "index": 11651
+ "index": 11671
}
},
{
@@ -141,12 +141,12 @@
"start": {
"line": 414,
"column": 16,
- "index": 11669
+ "index": 11689
},
"end": {
"line": 417,
"column": 3,
- "index": 11746
+ "index": 11766
}
},
{
@@ -156,12 +156,12 @@
"start": {
"line": 418,
"column": 16,
- "index": 11764
+ "index": 11784
},
"end": {
"line": 421,
"column": 3,
- "index": 11844
+ "index": 11864
}
}
]
\ No newline at end of file
diff --git a/apps/wallet-mobile/translations/messages/src/features/ReviewTx/common/hooks/useStrings.json b/apps/wallet-mobile/translations/messages/src/features/ReviewTx/common/hooks/useStrings.json
new file mode 100644
index 0000000000..f7ec21070a
--- /dev/null
+++ b/apps/wallet-mobile/translations/messages/src/features/ReviewTx/common/hooks/useStrings.json
@@ -0,0 +1,377 @@
+[
+ {
+ "id": "txReview.confirm",
+ "defaultMessage": "!!!Confirm",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 39,
+ "column": 11,
+ "index": 1785
+ },
+ "end": {
+ "line": 42,
+ "column": 3,
+ "index": 1852
+ }
+ },
+ {
+ "id": "txReview.title",
+ "defaultMessage": "!!!UTxOs",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 43,
+ "column": 9,
+ "index": 1863
+ },
+ "end": {
+ "line": 46,
+ "column": 3,
+ "index": 1926
+ }
+ },
+ {
+ "id": "txReview.tabLabel.utxos",
+ "defaultMessage": "!!!UTxOs",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 47,
+ "column": 12,
+ "index": 1940
+ },
+ "end": {
+ "line": 50,
+ "column": 3,
+ "index": 2012
+ }
+ },
+ {
+ "id": "txReview.tabLabel.overview",
+ "defaultMessage": "!!!Overview",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 51,
+ "column": 15,
+ "index": 2029
+ },
+ "end": {
+ "line": 54,
+ "column": 3,
+ "index": 2107
+ }
+ },
+ {
+ "id": "txReview.overview.wallet",
+ "defaultMessage": "!!!Wallet",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 55,
+ "column": 15,
+ "index": 2124
+ },
+ "end": {
+ "line": 58,
+ "column": 3,
+ "index": 2198
+ }
+ },
+ {
+ "id": "txReview.fee",
+ "defaultMessage": "!!!Fee",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 59,
+ "column": 12,
+ "index": 2212
+ },
+ "end": {
+ "line": 62,
+ "column": 3,
+ "index": 2271
+ }
+ },
+ {
+ "id": "txReview.overview.myWalletLabel",
+ "defaultMessage": "!!!Your Wallet",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 63,
+ "column": 17,
+ "index": 2290
+ },
+ "end": {
+ "line": 66,
+ "column": 3,
+ "index": 2376
+ }
+ },
+ {
+ "id": "txReview.overview.sendLabel",
+ "defaultMessage": "!!!Send",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 67,
+ "column": 13,
+ "index": 2391
+ },
+ "end": {
+ "line": 70,
+ "column": 3,
+ "index": 2466
+ }
+ },
+ {
+ "id": "txReview.overview.receiveToLabel",
+ "defaultMessage": "!!!To",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 71,
+ "column": 18,
+ "index": 2486
+ },
+ "end": {
+ "line": 74,
+ "column": 3,
+ "index": 2564
+ }
+ },
+ {
+ "id": "txReview.overview.receiveToScriptLabel",
+ "defaultMessage": "!!!To script",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 75,
+ "column": 24,
+ "index": 2590
+ },
+ "end": {
+ "line": 78,
+ "column": 3,
+ "index": 2681
+ }
+ },
+ {
+ "id": "txReview.utxos.utxosInputsLabel",
+ "defaultMessage": "!!!Inputs",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 79,
+ "column": 20,
+ "index": 2703
+ },
+ "end": {
+ "line": 82,
+ "column": 3,
+ "index": 2784
+ }
+ },
+ {
+ "id": "txReview.utxos.utxosOutputsLabel",
+ "defaultMessage": "!!!Outputs",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 83,
+ "column": 21,
+ "index": 2807
+ },
+ "end": {
+ "line": 86,
+ "column": 3,
+ "index": 2890
+ }
+ },
+ {
+ "id": "txReview.utxos.utxosYourAddressLabel",
+ "defaultMessage": "!!!Your address",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 87,
+ "column": 25,
+ "index": 2917
+ },
+ "end": {
+ "line": 90,
+ "column": 3,
+ "index": 3009
+ }
+ },
+ {
+ "id": "txReview.utxos.utxosForeignAddressLabel",
+ "defaultMessage": "!!!Foreign address",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 91,
+ "column": 28,
+ "index": 3039
+ },
+ "end": {
+ "line": 94,
+ "column": 3,
+ "index": 3137
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.overViewTab.title",
+ "defaultMessage": "!!!Overview",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 95,
+ "column": 12,
+ "index": 3151
+ },
+ "end": {
+ "line": 98,
+ "column": 3,
+ "index": 3242
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.jsonTab.title",
+ "defaultMessage": "!!!JSON",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 99,
+ "column": 8,
+ "index": 3252
+ },
+ "end": {
+ "line": 102,
+ "column": 3,
+ "index": 3335
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.jsonTab.metadata",
+ "defaultMessage": "!!!Metadata",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 103,
+ "column": 12,
+ "index": 3349
+ },
+ "end": {
+ "line": 106,
+ "column": 3,
+ "index": 3439
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.policyId.label",
+ "defaultMessage": "!!!Policy ID",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 107,
+ "column": 12,
+ "index": 3453
+ },
+ "end": {
+ "line": 110,
+ "column": 3,
+ "index": 3542
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.fingerprint.label",
+ "defaultMessage": "!!!Fingerprint",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 111,
+ "column": 15,
+ "index": 3559
+ },
+ "end": {
+ "line": 114,
+ "column": 3,
+ "index": 3653
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.overViewTab.name.label",
+ "defaultMessage": "!!!Name",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 115,
+ "column": 8,
+ "index": 3663
+ },
+ "end": {
+ "line": 118,
+ "column": 3,
+ "index": 3755
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.overViewTab.tokenSupply.label",
+ "defaultMessage": "!!!Token Supply",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 119,
+ "column": 15,
+ "index": 3772
+ },
+ "end": {
+ "line": 122,
+ "column": 3,
+ "index": 3879
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.overViewTab.symbol.label",
+ "defaultMessage": "!!!Symbol",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 123,
+ "column": 10,
+ "index": 3891
+ },
+ "end": {
+ "line": 126,
+ "column": 3,
+ "index": 3987
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.overViewTab.description.label",
+ "defaultMessage": "!!!Description",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 127,
+ "column": 15,
+ "index": 4004
+ },
+ "end": {
+ "line": 130,
+ "column": 3,
+ "index": 4110
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.overViewTab.details.label",
+ "defaultMessage": "!!!Details on",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 131,
+ "column": 11,
+ "index": 4123
+ },
+ "end": {
+ "line": 134,
+ "column": 3,
+ "index": 4224
+ }
+ },
+ {
+ "id": "txReview.tokenDetails.title",
+ "defaultMessage": "!!!Asset Details",
+ "file": "src/features/ReviewTx/common/hooks/useStrings.tsx",
+ "start": {
+ "line": 135,
+ "column": 21,
+ "index": 4247
+ },
+ "end": {
+ "line": 138,
+ "column": 3,
+ "index": 4331
+ }
+ }
+]
\ No newline at end of file
diff --git a/apps/wallet-mobile/translations/messages/src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.json b/apps/wallet-mobile/translations/messages/src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.json
index 4cfe771548..f08697a91d 100644
--- a/apps/wallet-mobile/translations/messages/src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.json
+++ b/apps/wallet-mobile/translations/messages/src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.json
@@ -4,14 +4,14 @@
"defaultMessage": "!!!Add token",
"file": "src/features/Send/useCases/ListAmountsToSend/ListAmountsToSendScreen.tsx",
"start": {
- "line": 207,
+ "line": 226,
"column": 12,
- "index": 6589
+ "index": 7420
},
"end": {
- "line": 210,
+ "line": 229,
"column": 3,
- "index": 6666
+ "index": 7497
}
}
]
\ No newline at end of file
diff --git a/apps/wallet-mobile/translations/messages/src/features/Settings/ManageCollateral/strings.json b/apps/wallet-mobile/translations/messages/src/features/Settings/ManageCollateral/strings.json
index 91042d5e7a..c1bf1a5728 100644
--- a/apps/wallet-mobile/translations/messages/src/features/Settings/ManageCollateral/strings.json
+++ b/apps/wallet-mobile/translations/messages/src/features/Settings/ManageCollateral/strings.json
@@ -4,14 +4,14 @@
"defaultMessage": "!!!Locked as collateral",
"file": "src/features/Settings/ManageCollateral/strings.ts",
"start": {
- "line": 17,
+ "line": 23,
"column": 22,
- "index": 720
+ "index": 1270
},
"end": {
- "line": 20,
+ "line": 26,
"column": 3,
- "index": 833
+ "index": 1383
}
},
{
@@ -19,14 +19,14 @@
"defaultMessage": "!!!If you want to return the amount locked as collateral to your balance press the remove icon",
"file": "src/features/Settings/ManageCollateral/strings.ts",
"start": {
- "line": 21,
+ "line": 27,
"column": 20,
- "index": 855
+ "index": 1405
},
"end": {
- "line": 24,
+ "line": 30,
"column": 3,
- "index": 1037
+ "index": 1587
}
},
{
@@ -34,14 +34,14 @@
"defaultMessage": "!!!Your collateral is gone, please generate new collateral",
"file": "src/features/Settings/ManageCollateral/strings.ts",
"start": {
- "line": 25,
+ "line": 31,
"column": 19,
- "index": 1058
+ "index": 1608
},
"end": {
- "line": 28,
+ "line": 34,
"column": 3,
- "index": 1203
+ "index": 1753
}
},
{
@@ -49,14 +49,14 @@
"defaultMessage": "!!!Generate collateral",
"file": "src/features/Settings/ManageCollateral/strings.ts",
"start": {
- "line": 29,
+ "line": 35,
"column": 22,
- "index": 1227
+ "index": 1777
},
"end": {
- "line": 32,
+ "line": 38,
"column": 3,
- "index": 1339
+ "index": 1889
}
},
{
@@ -64,14 +64,14 @@
"defaultMessage": "!!!Not enough funds",
"file": "src/features/Settings/ManageCollateral/strings.ts",
"start": {
- "line": 33,
+ "line": 39,
"column": 28,
- "index": 1369
+ "index": 1919
},
"end": {
- "line": 36,
+ "line": 42,
"column": 3,
- "index": 1484
+ "index": 2034
}
},
{
@@ -79,14 +79,14 @@
"defaultMessage": "!!!We could not find enough funds in this wallet to create collateral.",
"file": "src/features/Settings/ManageCollateral/strings.ts",
"start": {
- "line": 37,
+ "line": 43,
"column": 30,
- "index": 1516
+ "index": 2066
},
"end": {
- "line": 40,
+ "line": 46,
"column": 3,
- "index": 1684
+ "index": 2234
}
},
{
@@ -94,14 +94,104 @@
"defaultMessage": "!!!OK",
"file": "src/features/Settings/ManageCollateral/strings.ts",
"start": {
- "line": 41,
+ "line": 47,
"column": 25,
- "index": 1711
+ "index": 2261
},
"end": {
- "line": 44,
+ "line": 50,
"column": 3,
- "index": 1809
+ "index": 2359
+ }
+ },
+ {
+ "id": "components.settings.collateral.collateralInfoModalLabel",
+ "defaultMessage": "!!!Collateral creation",
+ "file": "src/features/Settings/ManageCollateral/strings.ts",
+ "start": {
+ "line": 51,
+ "column": 28,
+ "index": 2389
+ },
+ "end": {
+ "line": 54,
+ "column": 3,
+ "index": 2507
+ }
+ },
+ {
+ "id": "components.settings.collateral.collateralInfoModalTitle",
+ "defaultMessage": "!!!What is collateral?",
+ "file": "src/features/Settings/ManageCollateral/strings.ts",
+ "start": {
+ "line": 55,
+ "column": 28,
+ "index": 2537
+ },
+ "end": {
+ "line": 58,
+ "column": 3,
+ "index": 2655
+ }
+ },
+ {
+ "id": "components.settings.collateral.collateralInfoModalText",
+ "defaultMessage": "!!!The collateral mechanism is an important feature that has been designed to ensure successful smart contract execution. It is used to guarantee that Cardano nodes are compensated for their work in case phase-2 validation fails.",
+ "file": "src/features/Settings/ManageCollateral/strings.ts",
+ "start": {
+ "line": 59,
+ "column": 27,
+ "index": 2684
+ },
+ "end": {
+ "line": 63,
+ "column": 3,
+ "index": 3014
+ }
+ },
+ {
+ "id": "components.settings.collateral.initialCollateralInfoModalTitle",
+ "defaultMessage": "!!!Collateral creation",
+ "file": "src/features/Settings/ManageCollateral/strings.ts",
+ "start": {
+ "line": 64,
+ "column": 35,
+ "index": 3051
+ },
+ "end": {
+ "line": 67,
+ "column": 3,
+ "index": 3176
+ }
+ },
+ {
+ "id": "components.settings.collateral.initialCollateralInfoModalText",
+ "defaultMessage": "!!!The collateral mechanism is designed to ensure smart contracts on Cardano execute successfully. It guarantees that nodes are compensated for their work if a contract fails during validation.",
+ "file": "src/features/Settings/ManageCollateral/strings.ts",
+ "start": {
+ "line": 68,
+ "column": 34,
+ "index": 3212
+ },
+ "end": {
+ "line": 72,
+ "column": 3,
+ "index": 3513
+ }
+ },
+ {
+ "id": "components.settings.collateral.initialCollateralInfoModalButton",
+ "defaultMessage": "!!!Add collateral",
+ "file": "src/features/Settings/ManageCollateral/strings.ts",
+ "start": {
+ "line": 73,
+ "column": 36,
+ "index": 3551
+ },
+ "end": {
+ "line": 76,
+ "column": 3,
+ "index": 3672
}
}
]
\ No newline at end of file
diff --git a/apps/wallet-mobile/translations/messages/src/features/Settings/WalletSettings/WalletSettingsScreen.json b/apps/wallet-mobile/translations/messages/src/features/Settings/WalletSettings/WalletSettingsScreen.json
index 91a15ad429..0c242a6bf8 100644
--- a/apps/wallet-mobile/translations/messages/src/features/Settings/WalletSettings/WalletSettingsScreen.json
+++ b/apps/wallet-mobile/translations/messages/src/features/Settings/WalletSettings/WalletSettingsScreen.json
@@ -4,14 +4,14 @@
"defaultMessage": "!!!General",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 214,
+ "line": 227,
"column": 11,
- "index": 6741
+ "index": 7420
},
"end": {
- "line": 217,
+ "line": 230,
"column": 3,
- "index": 6839
+ "index": 7518
}
},
{
@@ -19,14 +19,14 @@
"defaultMessage": "!!!Actions",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 218,
+ "line": 231,
"column": 11,
- "index": 6852
+ "index": 7531
},
"end": {
- "line": 221,
+ "line": 234,
"column": 3,
- "index": 6950
+ "index": 7629
}
},
{
@@ -34,14 +34,14 @@
"defaultMessage": "!!!Switch wallet",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 222,
+ "line": 235,
"column": 16,
- "index": 6968
+ "index": 7647
},
"end": {
- "line": 225,
+ "line": 238,
"column": 3,
- "index": 7077
+ "index": 7756
}
},
{
@@ -49,14 +49,14 @@
"defaultMessage": "!!!Logout",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 226,
+ "line": 239,
"column": 10,
- "index": 7089
+ "index": 7768
},
"end": {
- "line": 229,
+ "line": 242,
"column": 3,
- "index": 7185
+ "index": 7864
}
},
{
@@ -64,14 +64,14 @@
"defaultMessage": "!!!Wallet name",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 230,
+ "line": 243,
"column": 14,
- "index": 7201
+ "index": 7880
},
"end": {
- "line": 233,
+ "line": 246,
"column": 3,
- "index": 7306
+ "index": 7985
}
},
{
@@ -79,14 +79,14 @@
"defaultMessage": "!!!Security",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 234,
+ "line": 247,
"column": 12,
- "index": 7320
+ "index": 7999
},
"end": {
- "line": 237,
+ "line": 250,
"column": 3,
- "index": 7420
+ "index": 8099
}
},
{
@@ -94,14 +94,14 @@
"defaultMessage": "!!!Change spending password",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 238,
+ "line": 251,
"column": 18,
- "index": 7440
+ "index": 8119
},
"end": {
- "line": 241,
+ "line": 254,
"column": 3,
- "index": 7562
+ "index": 8241
}
},
{
@@ -109,14 +109,14 @@
"defaultMessage": "!!!Easy transaction confirmation",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 242,
+ "line": 255,
"column": 20,
- "index": 7584
+ "index": 8263
},
"end": {
- "line": 245,
+ "line": 258,
"column": 3,
- "index": 7713
+ "index": 8392
}
},
{
@@ -124,14 +124,14 @@
"defaultMessage": "!!!Skip the password and approve transactions with biometrics",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 246,
+ "line": 259,
"column": 24,
- "index": 7739
+ "index": 8418
},
"end": {
- "line": 249,
+ "line": 262,
"column": 3,
- "index": 7901
+ "index": 8580
}
},
{
@@ -139,14 +139,14 @@
"defaultMessage": "!!!Remove wallet",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 250,
+ "line": 263,
"column": 16,
- "index": 7919
+ "index": 8598
},
"end": {
- "line": 253,
+ "line": 266,
"column": 3,
- "index": 8028
+ "index": 8707
}
},
{
@@ -154,14 +154,14 @@
"defaultMessage": "!!!Collateral",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 254,
+ "line": 267,
"column": 14,
- "index": 8044
+ "index": 8723
},
"end": {
- "line": 257,
+ "line": 270,
"column": 3,
- "index": 8115
+ "index": 8794
}
},
{
@@ -169,14 +169,14 @@
"defaultMessage": "!!!Multiple addresses",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 258,
+ "line": 271,
"column": 21,
- "index": 8138
+ "index": 8817
},
"end": {
- "line": 261,
+ "line": 274,
"column": 3,
- "index": 8224
+ "index": 8903
}
},
{
@@ -184,14 +184,14 @@
"defaultMessage": "!!!Single address",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 262,
+ "line": 275,
"column": 17,
- "index": 8243
+ "index": 8922
},
"end": {
- "line": 265,
+ "line": 278,
"column": 3,
- "index": 8321
+ "index": 9000
}
},
{
@@ -199,14 +199,14 @@
"defaultMessage": "!!!By enabling this you can operate with more wallet addresses",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 266,
+ "line": 279,
"column": 25,
- "index": 8348
+ "index": 9027
},
"end": {
- "line": 269,
+ "line": 282,
"column": 3,
- "index": 8479
+ "index": 9158
}
},
{
@@ -214,14 +214,14 @@
"defaultMessage": "!!!Network:",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 271,
+ "line": 284,
"column": 11,
- "index": 8540
+ "index": 9219
},
"end": {
- "line": 274,
+ "line": 287,
"column": 3,
- "index": 8606
+ "index": 9285
}
},
{
@@ -229,14 +229,14 @@
"defaultMessage": "!!!Wallet type:",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 275,
+ "line": 288,
"column": 14,
- "index": 8622
+ "index": 9301
},
"end": {
- "line": 278,
+ "line": 291,
"column": 3,
- "index": 8728
+ "index": 9407
}
},
{
@@ -244,14 +244,14 @@
"defaultMessage": "!!!Byron-era wallet",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 279,
+ "line": 292,
"column": 15,
- "index": 8745
+ "index": 9424
},
"end": {
- "line": 282,
+ "line": 295,
"column": 3,
- "index": 8856
+ "index": 9535
}
},
{
@@ -259,14 +259,14 @@
"defaultMessage": "!!!Shelley-era wallet",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 283,
+ "line": 296,
"column": 17,
- "index": 8875
+ "index": 9554
},
"end": {
- "line": 286,
+ "line": 299,
"column": 3,
- "index": 8990
+ "index": 9669
}
},
{
@@ -274,14 +274,14 @@
"defaultMessage": "!!!Unknown Wallet Type",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 287,
+ "line": 300,
"column": 21,
- "index": 9013
+ "index": 9692
},
"end": {
- "line": 290,
+ "line": 303,
"column": 3,
- "index": 9133
+ "index": 9812
}
},
{
@@ -289,14 +289,14 @@
"defaultMessage": "!!!About",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 291,
+ "line": 304,
"column": 9,
- "index": 9144
+ "index": 9823
},
"end": {
- "line": 294,
+ "line": 307,
"column": 3,
- "index": 9238
+ "index": 9917
}
},
{
@@ -304,14 +304,14 @@
"defaultMessage": "!!!Resync",
"file": "src/features/Settings/WalletSettings/WalletSettingsScreen.tsx",
"start": {
- "line": 295,
+ "line": 308,
"column": 10,
- "index": 9250
+ "index": 9929
},
"end": {
- "line": 298,
+ "line": 311,
"column": 3,
- "index": 9352
+ "index": 10031
}
}
]
\ No newline at end of file
diff --git a/apps/wallet-mobile/translations/messages/src/features/Transactions/TxHistoryNavigator.json b/apps/wallet-mobile/translations/messages/src/features/Transactions/TxHistoryNavigator.json
index ee02d523a1..cb695ac224 100644
--- a/apps/wallet-mobile/translations/messages/src/features/Transactions/TxHistoryNavigator.json
+++ b/apps/wallet-mobile/translations/messages/src/features/Transactions/TxHistoryNavigator.json
@@ -4,14 +4,14 @@
"defaultMessage": "!!!Receive",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 414,
+ "line": 404,
"column": 16,
- "index": 15157
+ "index": 14797
},
"end": {
- "line": 417,
+ "line": 407,
"column": 3,
- "index": 15246
+ "index": 14886
}
},
{
@@ -19,14 +19,14 @@
"defaultMessage": "!!!Address details",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 418,
+ "line": 408,
"column": 32,
- "index": 15280
+ "index": 14920
},
"end": {
- "line": 421,
+ "line": 411,
"column": 3,
- "index": 15393
+ "index": 15033
}
},
{
@@ -34,14 +34,14 @@
"defaultMessage": "!!!Swap",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 422,
+ "line": 412,
"column": 13,
- "index": 15408
+ "index": 15048
},
"end": {
- "line": 425,
+ "line": 415,
"column": 3,
- "index": 15481
+ "index": 15121
}
},
{
@@ -49,14 +49,14 @@
"defaultMessage": "!!!Swap from",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 426,
+ "line": 416,
"column": 17,
- "index": 15500
+ "index": 15140
},
"end": {
- "line": 429,
+ "line": 419,
"column": 3,
- "index": 15577
+ "index": 15217
}
},
{
@@ -64,14 +64,14 @@
"defaultMessage": "!!!Swap to",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 430,
+ "line": 420,
"column": 15,
- "index": 15594
+ "index": 15234
},
"end": {
- "line": 433,
+ "line": 423,
"column": 3,
- "index": 15667
+ "index": 15307
}
},
{
@@ -79,14 +79,14 @@
"defaultMessage": "!!!Slippage Tolerance",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 434,
+ "line": 424,
"column": 21,
- "index": 15690
+ "index": 15330
},
"end": {
- "line": 437,
+ "line": 427,
"column": 3,
- "index": 15785
+ "index": 15425
}
},
{
@@ -94,14 +94,14 @@
"defaultMessage": "!!!Select pool",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 438,
+ "line": 428,
"column": 14,
- "index": 15801
+ "index": 15441
},
"end": {
- "line": 441,
+ "line": 431,
"column": 3,
- "index": 15882
+ "index": 15522
}
},
{
@@ -109,14 +109,14 @@
"defaultMessage": "!!!Send",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 442,
+ "line": 432,
"column": 13,
- "index": 15897
+ "index": 15537
},
"end": {
- "line": 445,
+ "line": 435,
"column": 3,
- "index": 15977
+ "index": 15617
}
},
{
@@ -124,14 +124,14 @@
"defaultMessage": "!!!Scan QR code address",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 446,
+ "line": 436,
"column": 18,
- "index": 15997
+ "index": 15637
},
"end": {
- "line": 449,
+ "line": 439,
"column": 3,
- "index": 16098
+ "index": 15738
}
},
{
@@ -139,14 +139,14 @@
"defaultMessage": "!!!Select asset",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 450,
+ "line": 440,
"column": 20,
- "index": 16120
+ "index": 15760
},
"end": {
- "line": 453,
+ "line": 443,
"column": 3,
- "index": 16209
+ "index": 15849
}
},
{
@@ -154,14 +154,14 @@
"defaultMessage": "!!!Assets added",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 454,
+ "line": 444,
"column": 26,
- "index": 16237
+ "index": 15877
},
"end": {
- "line": 457,
+ "line": 447,
"column": 3,
- "index": 16338
+ "index": 15978
}
},
{
@@ -169,14 +169,14 @@
"defaultMessage": "!!!Edit amount",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 458,
+ "line": 448,
"column": 19,
- "index": 16359
+ "index": 15999
},
"end": {
- "line": 461,
+ "line": 451,
"column": 3,
- "index": 16452
+ "index": 16092
}
},
{
@@ -184,14 +184,14 @@
"defaultMessage": "!!!Confirm",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 462,
+ "line": 452,
"column": 16,
- "index": 16470
+ "index": 16110
},
"end": {
- "line": 465,
+ "line": 455,
"column": 3,
- "index": 16556
+ "index": 16196
}
},
{
@@ -199,14 +199,14 @@
"defaultMessage": "!!!Share this address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 466,
+ "line": 456,
"column": 19,
- "index": 16577
+ "index": 16217
},
"end": {
- "line": 472,
+ "line": 462,
"column": 3,
- "index": 16815
+ "index": 16455
}
},
{
@@ -214,14 +214,14 @@
"defaultMessage": "!!!Confirm transaction",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 473,
+ "line": 463,
"column": 27,
- "index": 16844
+ "index": 16484
},
"end": {
- "line": 476,
+ "line": 466,
"column": 3,
- "index": 16937
+ "index": 16577
}
},
{
@@ -229,14 +229,14 @@
"defaultMessage": "!!!Please scan a QR code",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 477,
+ "line": 467,
"column": 13,
- "index": 16952
+ "index": 16592
},
"end": {
- "line": 480,
+ "line": 470,
"column": 3,
- "index": 17027
+ "index": 16667
}
},
{
@@ -244,14 +244,14 @@
"defaultMessage": "!!!Success",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 481,
+ "line": 471,
"column": 25,
- "index": 17054
+ "index": 16694
},
"end": {
- "line": 484,
+ "line": 474,
"column": 3,
- "index": 17128
+ "index": 16768
}
},
{
@@ -259,14 +259,14 @@
"defaultMessage": "!!!Request specific amount",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 485,
+ "line": 475,
"column": 18,
- "index": 17148
+ "index": 16788
},
"end": {
- "line": 488,
+ "line": 478,
"column": 3,
- "index": 17262
+ "index": 16902
}
},
{
@@ -274,14 +274,14 @@
"defaultMessage": "!!!Buy/Sell ADA",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 489,
+ "line": 479,
"column": 28,
- "index": 17292
+ "index": 16932
},
"end": {
- "line": 492,
+ "line": 482,
"column": 3,
- "index": 17388
+ "index": 17028
}
},
{
@@ -289,14 +289,14 @@
"defaultMessage": "!!!Buy provider",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 493,
+ "line": 483,
"column": 29,
- "index": 17419
+ "index": 17059
},
"end": {
- "line": 496,
+ "line": 486,
"column": 3,
- "index": 17527
+ "index": 17167
}
},
{
@@ -304,14 +304,14 @@
"defaultMessage": "!!!Sell provider",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 497,
+ "line": 487,
"column": 30,
- "index": 17559
+ "index": 17199
},
"end": {
- "line": 500,
+ "line": 490,
"column": 3,
- "index": 17669
+ "index": 17309
}
},
{
@@ -319,14 +319,14 @@
"defaultMessage": "!!!Tx Details",
"file": "src/features/Transactions/TxHistoryNavigator.tsx",
"start": {
- "line": 501,
+ "line": 491,
"column": 18,
- "index": 17689
+ "index": 17329
},
"end": {
- "line": 504,
+ "line": 494,
"column": 3,
- "index": 17783
+ "index": 17423
}
}
]
\ No newline at end of file
diff --git a/packages/theme/src/base-palettes/dark-palette.ts b/packages/theme/src/base-palettes/dark-palette.ts
index 2d5582e877..8374a43683 100644
--- a/packages/theme/src/base-palettes/dark-palette.ts
+++ b/packages/theme/src/base-palettes/dark-palette.ts
@@ -39,6 +39,7 @@ export const darkPalette: BasePalette = {
black_static: '#000000',
white_static: '#FFFFFF',
+ green_static: '#08C29D',
sys_magenta_700: '#FFC0D0',
sys_magenta_600: '#FB9CB5',
diff --git a/packages/theme/src/base-palettes/light-palette.ts b/packages/theme/src/base-palettes/light-palette.ts
index dbddef3e92..5dedefc337 100644
--- a/packages/theme/src/base-palettes/light-palette.ts
+++ b/packages/theme/src/base-palettes/light-palette.ts
@@ -36,6 +36,7 @@ export const lightPalette: BasePalette = {
black_static: '#000000',
white_static: '#FFFFFF',
+ green_static: '#08C29D',
sys_magenta_700: '#CF053A',
sys_magenta_600: '#E80742',
diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts
index fa8554796a..00da13f171 100644
--- a/packages/theme/src/types.ts
+++ b/packages/theme/src/types.ts
@@ -59,6 +59,7 @@ export type BasePalette = {
black_static: HexColor
white_static: HexColor
+ green_static: HexColor
sys_magenta_700: HexColor
sys_magenta_600: HexColor