From ce59642cf7cbd11547f2df171e84b15a6d4a8bd6 Mon Sep 17 00:00:00 2001 From: Javier Bueno Date: Fri, 18 Oct 2024 18:06:40 +0200 Subject: [PATCH 1/5] feature(wallet-mobile): new tx review for stake delegation --- .../ios/yoroi.xcodeproj/project.pbxproj | 16 +- .../features/ReviewTx/common/TokenItem.tsx | 2 +- .../ReviewTx/common/hooks/useFormattedTx.tsx | 7 +- .../ReviewTx/common/hooks/useStrings.tsx | 25 ++ .../features/ReviewTx/common/operations.tsx | 140 ++++++++ .../src/features/ReviewTx/common/types.ts | 4 + .../Staking/Governance/common/helpers.tsx | 96 +----- .../src/kernel/i18n/locales/en-US.json | 7 +- apps/wallet-mobile/src/kernel/navigation.tsx | 9 - .../legacy/Dashboard/DashboardNavigator.tsx | 3 - .../DelegationConfirmation.stories.tsx | 69 ---- .../DelegationConfirmation.tsx | 203 ------------ .../Staking/DelegationConfirmation/index.ts | 1 - .../PoolTransition/usePoolTransition.tsx | 37 ++- .../Staking/StakingCenter/StakingCenter.tsx | 25 +- .../yoroi-wallets/cardano/delegationUtils.ts | 10 + .../ReviewTx/common/hooks/useStrings.json | 299 +++++++++++------- .../legacy/Dashboard/DashboardNavigator.json | 8 +- .../PoolTransition/usePoolTransition.json | 104 +++--- .../Staking/StakingCenter/StakingCenter.json | 16 +- 20 files changed, 501 insertions(+), 580 deletions(-) create mode 100644 apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx delete mode 100644 apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.stories.tsx delete mode 100644 apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.tsx delete mode 100644 apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/index.ts diff --git a/apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj b/apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj index 2069522357..9a42927d8f 100644 --- a/apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj +++ b/apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj @@ -837,11 +837,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = yoroi/yoroi.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 610; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = F8NVT2G2L4; + DEVELOPMENT_TEAM = F8NVT2G2L4; ENABLE_BITCODE = NO; ENVFILE = "$(PODS_ROOT)/../../.env"; INFOPLIST_FILE = yoroi/Info.plist; @@ -864,7 +863,6 @@ PRODUCT_BUNDLE_IDENTIFIER = com.emurgo.yoroi; PRODUCT_NAME = yoroi; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.emurgo.yoroi"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; @@ -882,11 +880,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = yoroi/yoroi.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 610; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = F8NVT2G2L4; + DEVELOPMENT_TEAM = F8NVT2G2L4; ENVFILE = "$(PODS_ROOT)/../../.env.production"; INFOPLIST_FILE = yoroi/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Yoroi; @@ -908,7 +905,6 @@ PRODUCT_BUNDLE_IDENTIFIER = com.emurgo.yoroi; PRODUCT_NAME = yoroi; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.emurgo.yoroi"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/TokenItem.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/TokenItem.tsx index 51ec99bbaa..fabea93b81 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/TokenItem.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/TokenItem.tsx @@ -48,7 +48,7 @@ export const TokenItem = ({ style={[styles.sentTokenItem, !isPrimaryToken && styles.notPrimarySentTokenItem]} disabled={isPrimaryToken} > - -{label} + {label} ) } diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx index 91ef9f2d30..e01bdae3ea 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx @@ -51,7 +51,12 @@ export const useFormattedTx = (data: TransactionBody): FormattedTx => { const formattedOutputs = useFormattedOutputs(wallet, outputs, portfolioTokenInfos) const formattedFee = formatFee(wallet, data) - return {inputs: formattedInputs, outputs: formattedOutputs, fee: formattedFee} + return { + inputs: formattedInputs, + outputs: formattedOutputs, + fee: formattedFee, + certificates: data.certs ?? null, + } } export const useFormattedInputs = ( diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx index b6e245d124..3858509fab 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx @@ -35,6 +35,11 @@ export const useStrings = () => { description: intl.formatMessage(messages.description), details: intl.formatMessage(messages.details), tokenDetailsTitle: intl.formatMessage(messages.tokenDetailsTitle), + registerStakingKey: intl.formatMessage(messages.registerStakingKey), + selectAbstain: intl.formatMessage(messages.selectAbstain), + selectNoConfidence: intl.formatMessage(messages.selectNoConfidence), + delegateVotingToDRep: intl.formatMessage(messages.delegateVotingToDRep), + delegateStake: intl.formatMessage(messages.delegateStake), } } @@ -151,4 +156,24 @@ const messages = defineMessages({ id: 'txReview.tokenDetails.title', defaultMessage: '!!!Asset Details', }, + registerStakingKey: { + id: 'txReview.operations.registerStakingKey', + defaultMessage: '!!!Register staking key deposit', + }, + selectAbstain: { + id: 'txReview.operations.selectAbstain', + defaultMessage: '!!!Select abstain', + }, + selectNoConfidence: { + id: 'txReview.operations.selectNoConfidence', + defaultMessage: '!!!Select no confidence', + }, + delegateVotingToDRep: { + id: 'txReview.operations.delegateVotingToDRep', + defaultMessage: '!!!Delegate voting to', + }, + delegateStake: { + id: 'txReview.operations.delegateStake', + defaultMessage: '!!!Stake entire wallet balance to', + }, }) diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx new file mode 100644 index 0000000000..37e67650b2 --- /dev/null +++ b/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx @@ -0,0 +1,140 @@ +import {PoolInfoApi} from '@emurgo/yoroi-lib' +import {useBech32DRepID} from '@yoroi/staking' +import {useTheme} from '@yoroi/theme' +import * as React from 'react' +import {Linking, StyleSheet, Text, View} from 'react-native' +import {TouchableOpacity} from 'react-native-gesture-handler' +import {useQuery} from 'react-query' + +import {Space} from '../../../components/Space/Space' +import {getPoolBech32Id} from '../../../yoroi-wallets/cardano/delegationUtils' +import {formatTokenWithText} from '../../../yoroi-wallets/utils/format' +import {asQuantity} from '../../../yoroi-wallets/utils/utils' +import {useSelectedNetwork} from '../../WalletManager/common/hooks/useSelectedNetwork' +import {useSelectedWallet} from '../../WalletManager/common/hooks/useSelectedWallet' +import {useStrings} from './hooks/useStrings' + +export const RegisterStakingKeyOperation = () => { + const {styles} = useStyles() + const strings = useStrings() + const {wallet} = useSelectedWallet() + + return ( + + {strings.registerStakingKey} + + + + + {formatTokenWithText(asQuantity(wallet.protocolParams.keyDeposit), wallet.portfolioPrimaryTokenInfo)} + + + ) +} +export const DelegateStakeOperation = ({poolId}: {poolId: string}) => { + const {styles} = useStyles() + const strings = useStrings() + const poolInfo = usePoolInfo({poolId}) + const {networkManager} = useSelectedNetwork() + + const poolInfoText = poolInfo != null ? `[${poolInfo.ticker}] ${poolInfo.name}` : poolId + + return ( + + {strings.delegateStake} + + + + Linking.openURL(networkManager.explorers.cardanoscan.pool(poolId))} + > + {poolInfoText} + + + ) +} + +export const usePoolInfo = ({poolId}: {poolId: string}) => { + const {networkManager} = useSelectedNetwork() + const poolInfoApi = React.useMemo( + () => new PoolInfoApi(networkManager.legacyApiBaseUrl), + [networkManager.legacyApiBaseUrl], + ) + const poolInfo = useQuery({ + queryKey: ['usePoolInfoStakeOperation', poolId], + queryFn: async () => { + const poolBech32Id = await getPoolBech32Id(poolId) + return poolInfoApi.getSingleExplorerPoolInfo(poolBech32Id) + }, + }) + + return poolInfo?.data ?? null +} + +export const AbstainOperation = () => { + const {styles} = useStyles() + const strings = useStrings() + + return ( + + {strings.selectAbstain} + + ) +} + +export const NoConfidenceOperation = () => { + const {styles} = useStyles() + const strings = useStrings() + + return ( + + {strings.selectNoConfidence} + + ) +} + +export const DelegateVotingToDrepOperation = ({drepID}: {drepID: string}) => { + const {styles} = useStyles() + const strings = useStrings() + + const {data: bech32DrepId} = useBech32DRepID(drepID) + + return ( + + {strings.delegateVotingToDRep} + + + + {bech32DrepId ?? drepID} + + ) +} + +const useStyles = () => { + const {color, atoms} = useTheme() + + const styles = StyleSheet.create({ + operation: { + ...atoms.flex_row, + ...atoms.justify_between, + ...atoms.align_start, + }, + operationLabel: { + ...atoms.body_2_md_regular, + color: color.text_gray_low, + }, + operationValue: { + ...atoms.flex_1, + ...atoms.text_right, + ...atoms.body_2_md_regular, + color: color.text_gray_medium, + }, + operationLink: { + ...atoms.body_2_md_regular, + color: color.text_primary_medium, + }, + }) + + return {styles} as const +} diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/types.ts b/apps/wallet-mobile/src/features/ReviewTx/common/types.ts index 04cf6aec6d..f06f1d2530 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/types.ts +++ b/apps/wallet-mobile/src/features/ReviewTx/common/types.ts @@ -1,4 +1,5 @@ import { + CertificatesJSON, TransactionBodyJSON, TransactionInputsJSON, TransactionOutputsJSON, @@ -56,9 +57,12 @@ export type FormattedTx = { inputs: FormattedInputs outputs: FormattedOutputs fee: FormattedFee + certificates: Certificates } export type FormattedMetadata = { hash: string | null metadata: {msg: Array} | null } + +export type Certificates = CertificatesJSON | null diff --git a/apps/wallet-mobile/src/features/Staking/Governance/common/helpers.tsx b/apps/wallet-mobile/src/features/Staking/Governance/common/helpers.tsx index 6a838019e9..b8ec96328e 100644 --- a/apps/wallet-mobile/src/features/Staking/Governance/common/helpers.tsx +++ b/apps/wallet-mobile/src/features/Staking/Governance/common/helpers.tsx @@ -4,30 +4,29 @@ import { governanceApiMaker, governanceManagerMaker, GovernanceProvider, - useBech32DRepID, useGovernance, useStakingKeyState, useUpdateLatestGovernanceAction, } from '@yoroi/staking' -import {useTheme} from '@yoroi/theme' import * as React from 'react' -import {StyleSheet, Text, View} from 'react-native' -import {Space} from '../../../../components/Space/Space' import {governaceAfterBlock} from '../../../../kernel/config' import {useWalletNavigation} from '../../../../kernel/navigation' import {YoroiWallet} from '../../../../yoroi-wallets/cardano/types' import {useStakingKey} from '../../../../yoroi-wallets/hooks' import {YoroiUnsignedTx} from '../../../../yoroi-wallets/types/yoroi' -import {formatTokenWithText} from '../../../../yoroi-wallets/utils/format' -import {asQuantity} from '../../../../yoroi-wallets/utils/utils' import {CardanoMobile} from '../../../../yoroi-wallets/wallets' +import { + AbstainOperation, + DelegateVotingToDrepOperation, + NoConfidenceOperation, + RegisterStakingKeyOperation, +} from '../../../ReviewTx/common/operations' import {useReviewTx} from '../../../ReviewTx/common/ReviewTxProvider' import {useBestBlock} from '../../../WalletManager/common/hooks/useBestBlock' import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet' import {GovernanceVote} from '../types' import {useNavigateTo} from './navigation' -import {useStrings} from './strings' export const useIsParticipatingInGovernance = (wallet: YoroiWallet) => { const stakingKeyHash = useStakingKey(wallet) @@ -100,7 +99,7 @@ export const useGovernanceActions = () => { }) => { let operations = [ - + , ] @@ -177,84 +176,3 @@ export const useGovernanceActions = () => { return {handleDelegateAction, handleAbstainAction, handleNoConfidenceAction} as const } - -const RegisterStakingKeyOperation = () => { - const {styles} = useStyles() - const strings = useStrings() - const {wallet} = useSelectedWallet() - - return ( - - {strings.registerStakingKey} - - - - - {formatTokenWithText(asQuantity(wallet.protocolParams.keyDeposit), wallet.portfolioPrimaryTokenInfo)} - - - ) -} - -const AbstainOperation = () => { - const {styles} = useStyles() - const strings = useStrings() - - return ( - - {strings.selectAbstain} - - ) -} - -const NoConfidenceOperation = () => { - const {styles} = useStyles() - const strings = useStrings() - - return ( - - {strings.selectNoConfidence} - - ) -} - -const DelegateOperation = ({drepID}: {drepID: string}) => { - const {styles} = useStyles() - const strings = useStrings() - - const {data: bech32DrepId} = useBech32DRepID(drepID) - - return ( - - {strings.delegateVotingToDRep} - - - - {bech32DrepId ?? drepID} - - ) -} - -const useStyles = () => { - const {color, atoms} = useTheme() - - const styles = StyleSheet.create({ - operation: { - ...atoms.flex_row, - ...atoms.justify_between, - ...atoms.align_start, - }, - operationLabel: { - ...atoms.body_2_md_regular, - color: color.text_gray_low, - }, - operationValue: { - ...atoms.flex_1, - ...atoms.text_right, - ...atoms.body_2_md_regular, - color: color.text_gray_medium, - }, - }) - - return {styles} as const -} diff --git a/apps/wallet-mobile/src/kernel/i18n/locales/en-US.json b/apps/wallet-mobile/src/kernel/i18n/locales/en-US.json index eb9f6b47dd..caeffe72a9 100644 --- a/apps/wallet-mobile/src/kernel/i18n/locales/en-US.json +++ b/apps/wallet-mobile/src/kernel/i18n/locales/en-US.json @@ -1246,5 +1246,10 @@ "txReview.tokenDetails.overViewTab.symbol.label": "Symbol", "txReview.tokenDetails.overViewTab.description.label": "Description", "txReview.tokenDetails.overViewTab.details.label": "Details on", - "txReview.tokenDetails.title": "Asset Details" + "txReview.tokenDetails.title": "Asset Details", + "txReview.operations.registerStakingKey": "Register staking key deposit", + "txReview.operations.selectAbstain": "Select abstain", + "txReview.operations.selectNoConfidence": "Select no confidence", + "txReview.operations.delegateVotingToDRep": "Delegate voting to", + "txReview.operations.delegateStake": "Stake entire wallet balance to" } diff --git a/apps/wallet-mobile/src/kernel/navigation.tsx b/apps/wallet-mobile/src/kernel/navigation.tsx index b11c7c0f6f..48d7e14131 100644 --- a/apps/wallet-mobile/src/kernel/navigation.tsx +++ b/apps/wallet-mobile/src/kernel/navigation.tsx @@ -9,7 +9,6 @@ import {Dimensions, InteractionManager, Platform, TouchableOpacity, TouchableOpa import {Icon} from '../components/Icon' import {Routes as StakingGovernanceRoutes} from '../features/Staking/Governance/common/navigation' -import {YoroiUnsignedTx} from '../yoroi-wallets/types/yoroi' import {compareArrays} from '../yoroi-wallets/utils/utils' // prettier-ignore @@ -191,10 +190,6 @@ export type SwapTokenRouteseNavigation = StackNavigationProp export type StakingCenterRoutes = { 'staking-center-main': undefined - 'delegation-confirmation': { - poolId: string - yoroiUnsignedTx: YoroiUnsignedTx - } 'delegation-failed-tx': undefined } @@ -274,10 +269,6 @@ export type BrowserRoutes = { export type DashboardRoutes = { 'staking-dashboard-main': undefined 'staking-center': NavigatorScreenParams - 'delegation-confirmation': { - poolId: string - yoroiUnsignedTx: YoroiUnsignedTx - } 'delegation-failed-tx': undefined } diff --git a/apps/wallet-mobile/src/legacy/Dashboard/DashboardNavigator.tsx b/apps/wallet-mobile/src/legacy/Dashboard/DashboardNavigator.tsx index 9e579faaa1..f536b3ffd7 100644 --- a/apps/wallet-mobile/src/legacy/Dashboard/DashboardNavigator.tsx +++ b/apps/wallet-mobile/src/legacy/Dashboard/DashboardNavigator.tsx @@ -9,7 +9,6 @@ import {NetworkTag} from '../../features/Settings/useCases/changeAppSettings/Cha import {useGovernanceManagerMaker} from '../../features/Staking/Governance/common/helpers' import {useSelectedWallet} from '../../features/WalletManager/common/hooks/useSelectedWallet' import {DashboardRoutes, defaultStackNavigationOptions} from '../../kernel/navigation' -import {DelegationConfirmation} from '../Staking/DelegationConfirmation' import {FailedTxScreen} from '../Staking/FailedTx/FailedTxScreen' import {StakingCenter} from '../Staking/StakingCenter' import {Dashboard} from './Dashboard' @@ -44,8 +43,6 @@ export const DashboardNavigator = () => { component={StakingCenter} /> - - diff --git a/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.stories.tsx b/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.stories.tsx deleted file mode 100644 index 52bd0458c5..0000000000 --- a/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.stories.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import {storiesOf} from '@storybook/react-native' -import React from 'react' -import {QueryClient, QueryClientProvider} from 'react-query' - -import {RouteProvider} from '../../../../.storybook/decorators' -import {StakingCenterRoutes} from '../../../kernel/navigation' -import {mocks} from '../../../yoroi-wallets/mocks/wallet' -import {WalletManagerProviderMock} from '../../../yoroi-wallets/mocks/WalletManagerProviderMock' -import {DelegationConfirmation} from './DelegationConfirmation' - -storiesOf('DelegationConfirmation', module) - .add('Default', () => ( - - - - - - - - )) - .add('loading', () => ( - - - - - - - - )) - .add('error', () => ( - - - - - - - - )) - -const params: StakingCenterRoutes['delegation-confirmation'] = { - poolId: '6777ed5eac05ab8bf55d073424132e200935c8d3be62fb00f5252cd27a9fe6e5', - yoroiUnsignedTx: { - ...mocks.yoroiUnsignedTx, - staking: { - registrations: [], - deregistrations: [], - delegations: [{address: 'rewardAddress', amounts: {'.': '123456789'}}], - withdrawals: [], - }, - }, -} diff --git a/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.tsx b/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.tsx deleted file mode 100644 index a55acad821..0000000000 --- a/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.tsx +++ /dev/null @@ -1,203 +0,0 @@ -import {useTheme} from '@yoroi/theme' -import React, {useEffect, useState} from 'react' -import {defineMessages, useIntl} from 'react-intl' -import {Platform, ScrollView, StyleSheet, View} from 'react-native' -import {useQueryClient} from 'react-query' - -import {ConfirmTx} from '../../../components/ConfirmTx/ConfirmTx' -import {KeyboardSpacer} from '../../../components/KeyboardSpacer' -import {Space} from '../../../components/Space/Space' -import {Text} from '../../../components/Text' -import {ValidatedTextInput} from '../../../components/ValidatedTextInput' -import {useSelectedWallet} from '../../../features/WalletManager/common/hooks/useSelectedWallet' -import {debugWalletInfo, features} from '../../../kernel/features' -import globalMessages, {txLabels} from '../../../kernel/i18n/global-messages' -import {StakingCenterRoutes, useParams, useWalletNavigation} from '../../../kernel/navigation' -import {formatTokenAmount} from '../../../yoroi-wallets/utils/format' -import {Amounts, Entries} from '../../../yoroi-wallets/utils/utils' -import {useStakePoolInfoAndHistory} from '../../Dashboard/StakePoolInfo' -import {Instructions as HWInstructions} from '../../HW' - -type Params = StakingCenterRoutes['delegation-confirmation'] - -const isParams = (params?: Params | object | undefined): params is Params => { - return ( - !!params && - 'yoroiUnsignedTx' in params && - typeof params.yoroiUnsignedTx === 'object' && - 'poolId' in params && - typeof params.poolId === 'string' - ) -} - -export const DelegationConfirmation = () => { - const {resetToTxHistory} = useWalletNavigation() - const {wallet, meta} = useSelectedWallet() - const strings = useStrings() - const styles = useStyles() - const queryClient = useQueryClient() - - const {poolId, yoroiUnsignedTx} = useParams(isParams) - - if (!yoroiUnsignedTx.staking?.delegations) throw new Error('invalid transaction') - const stakingAmount = Amounts.getAmount( - Entries.toAmounts(yoroiUnsignedTx.staking.delegations), - wallet.portfolioPrimaryTokenInfo.id, - ) - const [password, setPassword] = useState('') - const [useUSB, setUseUSB] = useState(false) - - useEffect(() => { - if (features.prefillWalletInfo && __DEV__) setPassword(debugWalletInfo.PASSWORD) - }, []) - - const onSuccess = () => { - queryClient.resetQueries([wallet.id, 'stakingInfo']) - resetToTxHistory() - } - - const fee = formatTokenAmount( - yoroiUnsignedTx.fee[wallet.portfolioPrimaryTokenInfo.id], - wallet.portfolioPrimaryTokenInfo, - ) - - return ( - - - - {strings.stakePoolName} - - - - - - {strings.stakePoolHash} - - - {poolId} - - - - - - {`+ ${fee} ${strings.ofFees}`} - - - {/* requires a handler so we pass on a dummy function */} - - undefined} - editable={false} - value={formatTokenAmount(stakingAmount.quantity, wallet.portfolioPrimaryTokenInfo)} - label={strings.amount} - /> - - - {!meta.isEasyConfirmationEnabled && !meta.isHW && ( - - - - )} - - - {strings.rewardsExplanation} - - - {meta.isHW && } - - - - - - - {/* hack to fix weird KeyboardAvoidingView bug in THIS SCREEN */} - {Platform.OS === 'ios' && } - - ) -} - -const StakePoolName = ({stakePoolId}: {stakePoolId: string}) => { - const strings = useStrings() - const styles = useStyles() - const {wallet} = useSelectedWallet() - const {stakePoolInfoAndHistory, isLoading, error} = useStakePoolInfoAndHistory({wallet, stakePoolId}) - - return ( - - {isLoading ? '...' : error ? strings.unknownPool : stakePoolInfoAndHistory?.info.name} - - ) -} - -const useStyles = () => { - const {atoms, color} = useTheme() - const styles = StyleSheet.create({ - container: { - backgroundColor: color.bg_color_max, - ...atoms.px_lg, - ...atoms.pb_2xl, - flex: 1, - }, - itemBlock: { - ...atoms.pt_2xl, - }, - heading: { - color: color.gray_900, - ...atoms.body_1_lg_medium, - }, - text: { - color: color.gray_900, - ...atoms.body_2_md_regular, - }, - fees: { - textAlign: 'right', - color: color.gray_900, - }, - }) - return styles -} - -const useStrings = () => { - const intl = useIntl() - - return { - stakePoolName: intl.formatMessage(globalMessages.stakePoolName), - stakePoolHash: intl.formatMessage(globalMessages.stakePoolHash), - ofFees: intl.formatMessage(messages.ofFees), - amount: intl.formatMessage(txLabels.amount), - password: intl.formatMessage(txLabels.password), - rewardsExplanation: intl.formatMessage(messages.rewardsExplanation), - delegateButtonLabel: intl.formatMessage(messages.delegateButtonLabel), - unknownPool: intl.formatMessage(messages.unknownPool), - } -} - -const messages = defineMessages({ - delegateButtonLabel: { - id: 'components.stakingcenter.confirmDelegation.delegateButtonLabel', - defaultMessage: '!!!Delegate', - }, - ofFees: { - id: 'components.stakingcenter.confirmDelegation.ofFees', - defaultMessage: '!!!of fees', - }, - rewardsExplanation: { - id: 'components.stakingcenter.confirmDelegation.rewardsExplanation', - defaultMessage: '!!!Current approximation of rewards that you will receive per epoch:', - }, - unknownPool: { - id: 'components.delegationsummary.delegatedStakepoolInfo.unknownPool', - defaultMessage: '!!!Unknown pool', - }, -}) diff --git a/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/index.ts b/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/index.ts deleted file mode 100644 index 3007ac4817..0000000000 --- a/apps/wallet-mobile/src/legacy/Staking/DelegationConfirmation/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './DelegationConfirmation' diff --git a/apps/wallet-mobile/src/legacy/Staking/PoolTransition/usePoolTransition.tsx b/apps/wallet-mobile/src/legacy/Staking/PoolTransition/usePoolTransition.tsx index 65cebf2c76..d6bd535031 100644 --- a/apps/wallet-mobile/src/legacy/Staking/PoolTransition/usePoolTransition.tsx +++ b/apps/wallet-mobile/src/legacy/Staking/PoolTransition/usePoolTransition.tsx @@ -7,9 +7,12 @@ import * as React from 'react' import {defineMessages, useIntl} from 'react-intl' import {useQuery} from 'react-query' +import {DelegateStakeOperation} from '../../../features/ReviewTx/common/operations' +import {useReviewTx} from '../../../features/ReviewTx/common/ReviewTxProvider' import {useSelectedNetwork} from '../../../features/WalletManager/common/hooks/useSelectedNetwork' import {useSelectedWallet} from '../../../features/WalletManager/common/hooks/useSelectedWallet' import {features} from '../../../kernel/features' +import {AppRouteNavigation, StakingCenterRouteNavigation, useWalletNavigation} from '../../../kernel/navigation' import {YoroiWallet} from '../../../yoroi-wallets/cardano/types' import {asQuantity, Quantities} from '../../../yoroi-wallets/utils/utils' import {useStakingInfo} from '../../Dashboard/StakePoolInfos' @@ -33,9 +36,12 @@ const createDelegationTx = async (wallet: YoroiWallet, poolId: string, meta: Wal } export const usePoolTransition = () => { - const navigation = useNavigation() + const navigation = useNavigation() + const {wallet, meta} = useSelectedWallet() const {networkManager} = useSelectedNetwork() + const {navigateToTxReview, resetToTxHistory} = useWalletNavigation() + const {unsignedTxChanged, onSuccessChanged, onErrorChanged, operationsChanged} = useReviewTx() const {stakingInfo, isLoading} = useStakingInfo(wallet) const poolInfoApi = React.useMemo( () => new PoolInfoApi(networkManager.legacyApiBaseUrl), @@ -59,17 +65,13 @@ export const usePoolTransition = () => { const navigateToUpdate = React.useCallback(async () => { try { const yoroiUnsignedTx = await createDelegationTx(wallet, poolId, meta) - navigation.navigate('manage-wallets', { - screen: 'staking-dashboard', - params: { - screen: 'delegation-confirmation', - initial: false, - params: { - poolId, - yoroiUnsignedTx, - }, - }, + operationsChanged([]) + unsignedTxChanged(yoroiUnsignedTx) + onSuccessChanged(() => { + resetToTxHistory() }) + onErrorChanged(() => navigation.navigate('delegation-failed-tx')) + navigateToTxReview() } catch (err) { navigation.navigate('manage-wallets', { screen: 'staking-dashboard', @@ -79,7 +81,18 @@ export const usePoolTransition = () => { }, }) } - }, [meta, navigation, poolId, wallet]) + }, [ + wallet, + poolId, + meta, + operationsChanged, + unsignedTxChanged, + onSuccessChanged, + onErrorChanged, + navigateToTxReview, + resetToTxHistory, + navigation, + ]) return { ...poolTransitionQuery, diff --git a/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx b/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx index 344d817bfa..425290317f 100644 --- a/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx +++ b/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx @@ -5,9 +5,12 @@ import {defineMessages, useIntl} from 'react-intl' import {StyleSheet, View} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' import {WebView, WebViewMessageEvent} from 'react-native-webview' +import {useQueryClient} from 'react-query' import {PleaseWaitModal} from '../../../components/PleaseWaitModal' import {Spacer} from '../../../components/Spacer/Spacer' +import {DelegateStakeOperation, RegisterStakingKeyOperation} from '../../../features/ReviewTx/common/operations' +import {useReviewTx} from '../../../features/ReviewTx/common/ReviewTxProvider' import {useSelectedWallet} from '../../../features/WalletManager/common/hooks/useSelectedWallet' import {useWalletManager} from '../../../features/WalletManager/context/WalletManagerProvider' import {showErrorDialog} from '../../../kernel/dialogs' @@ -15,9 +18,9 @@ import {useLanguage} from '../../../kernel/i18n' import globalMessages from '../../../kernel/i18n/global-messages' import {logger} from '../../../kernel/logger/logger' import {useMetrics} from '../../../kernel/metrics/metricsManager' -import {StakingCenterRouteNavigation} from '../../../kernel/navigation' +import {StakingCenterRouteNavigation, useWalletNavigation} from '../../../kernel/navigation' import {NotEnoughMoneyToSendError} from '../../../yoroi-wallets/cardano/types' -import {useStakingTx} from '../../Dashboard/StakePoolInfos' +import {useStakingInfo, useStakingTx} from '../../Dashboard/StakePoolInfos' import {PoolDetailScreen} from '../PoolDetails' export const StakingCenter = () => { @@ -25,12 +28,17 @@ export const StakingCenter = () => { const navigation = useNavigation() const {isDark} = useTheme() const {styles} = useStyles() + const queryClient = useQueryClient() const {languageCode} = useLanguage() const {wallet, meta} = useSelectedWallet() const {walletManager} = useWalletManager() const {track} = useMetrics() const {plate} = walletManager.checksum(wallet.publicKeyHex) + const {navigateToTxReview, resetToTxHistory} = useWalletNavigation() + const {unsignedTxChanged, onSuccessChanged, onErrorChanged, operationsChanged} = useReviewTx() + const stakingInfo = useStakingInfo(wallet, {suspense: true}) + const hasStakingKeyRegistered = stakingInfo?.data?.status !== 'not-registered' useFocusEffect( React.useCallback(() => { @@ -49,10 +57,17 @@ export const StakingCenter = () => { onSuccess: (yoroiUnsignedTx) => { if (selectedPoolId == null) return - navigation.navigate('delegation-confirmation', { - poolId: selectedPoolId, - yoroiUnsignedTx, + let operations = [] + if (!hasStakingKeyRegistered) operations = [, ...operations] + + operationsChanged(operations) + unsignedTxChanged(yoroiUnsignedTx) + onSuccessChanged(() => { + queryClient.resetQueries([wallet.id, 'stakingInfo']) + resetToTxHistory() }) + onErrorChanged(() => navigation.navigate('delegation-failed-tx')) + navigateToTxReview() }, onError: (error) => { if (error instanceof NotEnoughMoneyToSendError) { diff --git a/apps/wallet-mobile/src/yoroi-wallets/cardano/delegationUtils.ts b/apps/wallet-mobile/src/yoroi-wallets/cardano/delegationUtils.ts index c524c6d73e..cadc956a99 100644 --- a/apps/wallet-mobile/src/yoroi-wallets/cardano/delegationUtils.ts +++ b/apps/wallet-mobile/src/yoroi-wallets/cardano/delegationUtils.ts @@ -112,6 +112,16 @@ const isValidPoolId = async (poolId: string): Promise => { } } +export const getPoolBech32Id = async (poolId: string) => { + const {csl, release} = wrappedCsl() + try { + const keyHash = await csl.Ed25519KeyHash.fromHex(poolId) + return keyHash.toBech32('pool') + } finally { + release() + } +} + const isValidPoolHash = async (poolHash: string): Promise => { if (poolHash.length === 0) return false 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 index fdeb1cc006..9e1a48b052 100644 --- 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 @@ -4,14 +4,14 @@ "defaultMessage": "!!!Confirm", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 42, + "line": 47, "column": 11, - "index": 1976 + "index": 2325 }, "end": { - "line": 45, + "line": 50, "column": 3, - "index": 2043 + "index": 2392 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!UTxOs", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 46, + "line": 51, "column": 9, - "index": 2054 + "index": 2403 }, "end": { - "line": 49, + "line": 54, "column": 3, - "index": 2117 + "index": 2466 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!UTxOs", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 50, + "line": 55, "column": 12, - "index": 2131 + "index": 2480 }, "end": { - "line": 53, + "line": 58, "column": 3, - "index": 2203 + "index": 2552 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Overview", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 54, + "line": 59, "column": 15, - "index": 2220 + "index": 2569 }, "end": { - "line": 57, + "line": 62, "column": 3, - "index": 2298 + "index": 2647 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!!Metadata", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 58, + "line": 63, "column": 15, - "index": 2315 + "index": 2664 }, "end": { - "line": 61, + "line": 66, "column": 3, - "index": 2396 + "index": 2745 } }, { @@ -79,14 +79,14 @@ "defaultMessage": "!!!Metadata hash", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 62, + "line": 67, "column": 16, - "index": 2414 + "index": 2763 }, "end": { - "line": 65, + "line": 70, "column": 3, - "index": 2501 + "index": 2850 } }, { @@ -94,14 +94,14 @@ "defaultMessage": "!!!Metadata", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 66, + "line": 71, "column": 21, - "index": 2524 + "index": 2873 }, "end": { - "line": 69, + "line": 74, "column": 3, - "index": 2611 + "index": 2960 } }, { @@ -109,14 +109,14 @@ "defaultMessage": "!!!Wallet", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 70, + "line": 75, "column": 15, - "index": 2628 + "index": 2977 }, "end": { - "line": 73, + "line": 78, "column": 3, - "index": 2702 + "index": 3051 } }, { @@ -124,14 +124,14 @@ "defaultMessage": "!!!Fee", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 74, + "line": 79, "column": 12, - "index": 2716 + "index": 3065 }, "end": { - "line": 77, + "line": 82, "column": 3, - "index": 2775 + "index": 3124 } }, { @@ -139,14 +139,14 @@ "defaultMessage": "!!!Your Wallet", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 78, + "line": 83, "column": 17, - "index": 2794 + "index": 3143 }, "end": { - "line": 81, + "line": 86, "column": 3, - "index": 2880 + "index": 3229 } }, { @@ -154,14 +154,14 @@ "defaultMessage": "!!!Send", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 82, + "line": 87, "column": 13, - "index": 2895 + "index": 3244 }, "end": { - "line": 85, + "line": 90, "column": 3, - "index": 2970 + "index": 3319 } }, { @@ -169,14 +169,14 @@ "defaultMessage": "!!!To", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 86, + "line": 91, "column": 18, - "index": 2990 + "index": 3339 }, "end": { - "line": 89, + "line": 94, "column": 3, - "index": 3068 + "index": 3417 } }, { @@ -184,14 +184,14 @@ "defaultMessage": "!!!To script", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 90, + "line": 95, "column": 24, - "index": 3094 + "index": 3443 }, "end": { - "line": 93, + "line": 98, "column": 3, - "index": 3185 + "index": 3534 } }, { @@ -199,14 +199,14 @@ "defaultMessage": "!!!Inputs", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 94, + "line": 99, "column": 20, - "index": 3207 + "index": 3556 }, "end": { - "line": 97, + "line": 102, "column": 3, - "index": 3288 + "index": 3637 } }, { @@ -214,14 +214,14 @@ "defaultMessage": "!!!Outputs", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 98, + "line": 103, "column": 21, - "index": 3311 + "index": 3660 }, "end": { - "line": 101, + "line": 106, "column": 3, - "index": 3394 + "index": 3743 } }, { @@ -229,14 +229,14 @@ "defaultMessage": "!!!Your address", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 102, + "line": 107, "column": 25, - "index": 3421 + "index": 3770 }, "end": { - "line": 105, + "line": 110, "column": 3, - "index": 3513 + "index": 3862 } }, { @@ -244,14 +244,14 @@ "defaultMessage": "!!!Foreign address", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 106, + "line": 111, "column": 28, - "index": 3543 + "index": 3892 }, "end": { - "line": 109, + "line": 114, "column": 3, - "index": 3641 + "index": 3990 } }, { @@ -259,14 +259,14 @@ "defaultMessage": "!!!Overview", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 110, + "line": 115, "column": 12, - "index": 3655 + "index": 4004 }, "end": { - "line": 113, + "line": 118, "column": 3, - "index": 3746 + "index": 4095 } }, { @@ -274,14 +274,14 @@ "defaultMessage": "!!!JSON", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 114, + "line": 119, "column": 8, - "index": 3756 + "index": 4105 }, "end": { - "line": 117, + "line": 122, "column": 3, - "index": 3839 + "index": 4188 } }, { @@ -289,14 +289,14 @@ "defaultMessage": "!!!Metadata", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 118, + "line": 123, "column": 12, - "index": 3853 + "index": 4202 }, "end": { - "line": 121, + "line": 126, "column": 3, - "index": 3943 + "index": 4292 } }, { @@ -304,14 +304,14 @@ "defaultMessage": "!!!Policy ID", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 122, + "line": 127, "column": 12, - "index": 3957 + "index": 4306 }, "end": { - "line": 125, + "line": 130, "column": 3, - "index": 4046 + "index": 4395 } }, { @@ -319,14 +319,14 @@ "defaultMessage": "!!!Fingerprint", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 126, + "line": 131, "column": 15, - "index": 4063 + "index": 4412 }, "end": { - "line": 129, + "line": 134, "column": 3, - "index": 4157 + "index": 4506 } }, { @@ -334,14 +334,14 @@ "defaultMessage": "!!!Name", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 130, + "line": 135, "column": 8, - "index": 4167 + "index": 4516 }, "end": { - "line": 133, + "line": 138, "column": 3, - "index": 4259 + "index": 4608 } }, { @@ -349,14 +349,14 @@ "defaultMessage": "!!!Token Supply", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 134, + "line": 139, "column": 15, - "index": 4276 + "index": 4625 }, "end": { - "line": 137, + "line": 142, "column": 3, - "index": 4383 + "index": 4732 } }, { @@ -364,14 +364,14 @@ "defaultMessage": "!!!Symbol", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 138, + "line": 143, "column": 10, - "index": 4395 + "index": 4744 }, "end": { - "line": 141, + "line": 146, "column": 3, - "index": 4491 + "index": 4840 } }, { @@ -379,14 +379,14 @@ "defaultMessage": "!!!Description", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 142, + "line": 147, "column": 15, - "index": 4508 + "index": 4857 }, "end": { - "line": 145, + "line": 150, "column": 3, - "index": 4614 + "index": 4963 } }, { @@ -394,14 +394,14 @@ "defaultMessage": "!!!Details on", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 146, + "line": 151, "column": 11, - "index": 4627 + "index": 4976 }, "end": { - "line": 149, + "line": 154, "column": 3, - "index": 4728 + "index": 5077 } }, { @@ -409,14 +409,89 @@ "defaultMessage": "!!!Asset Details", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 150, + "line": 155, "column": 21, - "index": 4751 + "index": 5100 + }, + "end": { + "line": 158, + "column": 3, + "index": 5184 + } + }, + { + "id": "txReview.operations.registerStakingKey", + "defaultMessage": "!!!Register staking key deposit", + "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", + "start": { + "line": 159, + "column": 22, + "index": 5208 + }, + "end": { + "line": 162, + "column": 3, + "index": 5318 + } + }, + { + "id": "txReview.operations.selectAbstain", + "defaultMessage": "!!!Select abstain", + "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", + "start": { + "line": 163, + "column": 17, + "index": 5337 + }, + "end": { + "line": 166, + "column": 3, + "index": 5428 + } + }, + { + "id": "txReview.operations.selectNoConfidence", + "defaultMessage": "!!!Select no confidence", + "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", + "start": { + "line": 167, + "column": 22, + "index": 5452 + }, + "end": { + "line": 170, + "column": 3, + "index": 5554 + } + }, + { + "id": "txReview.operations.delegateVotingToDRep", + "defaultMessage": "!!!Delegate voting to", + "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", + "start": { + "line": 171, + "column": 24, + "index": 5580 + }, + "end": { + "line": 174, + "column": 3, + "index": 5682 + } + }, + { + "id": "txReview.operations.delegateStake", + "defaultMessage": "!!!Stake entire wallet balance to", + "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", + "start": { + "line": 175, + "column": 17, + "index": 5701 }, "end": { - "line": 153, + "line": 178, "column": 3, - "index": 4835 + "index": 5808 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/legacy/Dashboard/DashboardNavigator.json b/apps/wallet-mobile/translations/messages/src/legacy/Dashboard/DashboardNavigator.json index 7f80182884..27dd43c7e4 100644 --- a/apps/wallet-mobile/translations/messages/src/legacy/Dashboard/DashboardNavigator.json +++ b/apps/wallet-mobile/translations/messages/src/legacy/Dashboard/DashboardNavigator.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Staking Center", "file": "src/legacy/Dashboard/DashboardNavigator.tsx", "start": { - "line": 64, + "line": 61, "column": 9, - "index": 2092 + "index": 1927 }, "end": { - "line": 67, + "line": 64, "column": 3, - "index": 2180 + "index": 2015 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/legacy/Staking/PoolTransition/usePoolTransition.json b/apps/wallet-mobile/translations/messages/src/legacy/Staking/PoolTransition/usePoolTransition.json index 14002a4758..1ec5530969 100644 --- a/apps/wallet-mobile/translations/messages/src/legacy/Staking/PoolTransition/usePoolTransition.json +++ b/apps/wallet-mobile/translations/messages/src/legacy/Staking/PoolTransition/usePoolTransition.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Upgrade your stake pool", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 114, + "line": 127, "column": 9, - "index": 4057 + "index": 4719 }, "end": { - "line": 117, + "line": 130, "column": 3, - "index": 4155 + "index": 4817 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!The current stake pool you're using will soon close. Migrate to the new EMURGO pool to sustain reward generation.", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 118, + "line": 131, "column": 11, - "index": 4168 + "index": 4830 }, "end": { - "line": 122, + "line": 135, "column": 3, - "index": 4364 + "index": 5026 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!The current stake pool you're using is decommissioned and NOT generating reward anymore. Update it to continue earning", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 123, + "line": 136, "column": 16, - "index": 4382 + "index": 5044 }, "end": { - "line": 127, + "line": 140, "column": 3, - "index": 4588 + "index": 5250 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Current pool", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 128, + "line": 141, "column": 15, - "index": 4605 + "index": 5267 }, "end": { - "line": 131, + "line": 144, "column": 3, - "index": 4698 + "index": 5360 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!!New pool", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 132, + "line": 145, "column": 11, - "index": 4711 + "index": 5373 }, "end": { - "line": 135, + "line": 148, "column": 3, - "index": 4796 + "index": 5458 } }, { @@ -79,14 +79,14 @@ "defaultMessage": "!!!Estimated ROA", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 136, + "line": 149, "column": 16, - "index": 4814 + "index": 5476 }, "end": { - "line": 139, + "line": 152, "column": 3, - "index": 4909 + "index": 5571 } }, { @@ -94,14 +94,14 @@ "defaultMessage": "!!!Fee", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 140, + "line": 153, "column": 7, - "index": 4918 + "index": 5580 }, "end": { - "line": 143, + "line": 156, "column": 3, - "index": 4994 + "index": 5656 } }, { @@ -109,14 +109,14 @@ "defaultMessage": "!!!This pool continues to generate staking rewards", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 144, + "line": 157, "column": 24, - "index": 5020 + "index": 5682 }, "end": { - "line": 147, + "line": 160, "column": 3, - "index": 5157 + "index": 5819 } }, { @@ -124,14 +124,14 @@ "defaultMessage": "!!!This pool is NOT generating staking rewards anymore", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 148, + "line": 161, "column": 17, - "index": 5176 + "index": 5838 }, "end": { - "line": 151, + "line": 164, "column": 3, - "index": 5310 + "index": 5972 } }, { @@ -139,14 +139,14 @@ "defaultMessage": "!!!This pool will stop generating rewards in", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 152, + "line": 165, "column": 23, - "index": 5335 + "index": 5997 }, "end": { - "line": 155, + "line": 168, "column": 3, - "index": 5465 + "index": 6127 } }, { @@ -154,14 +154,14 @@ "defaultMessage": "!!!Skip and stop receiving rewards", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 156, + "line": 169, "column": 17, - "index": 5484 + "index": 6146 }, "end": { - "line": 159, + "line": 172, "column": 3, - "index": 5598 + "index": 6260 } }, { @@ -169,14 +169,14 @@ "defaultMessage": "!!!Update now and keep earning", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 160, + "line": 173, "column": 21, - "index": 5621 + "index": 6283 }, "end": { - "line": 163, + "line": 176, "column": 3, - "index": 5735 + "index": 6397 } }, { @@ -184,14 +184,14 @@ "defaultMessage": "!!!Update pool", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 164, + "line": 177, "column": 10, - "index": 5747 + "index": 6409 }, "end": { - "line": 167, + "line": 180, "column": 3, - "index": 5834 + "index": 6496 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/legacy/Staking/StakingCenter/StakingCenter.json b/apps/wallet-mobile/translations/messages/src/legacy/Staking/StakingCenter/StakingCenter.json index 30704959bc..4f55b6775b 100644 --- a/apps/wallet-mobile/translations/messages/src/legacy/Staking/StakingCenter/StakingCenter.json +++ b/apps/wallet-mobile/translations/messages/src/legacy/Staking/StakingCenter/StakingCenter.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Invalid Pool Data", "file": "src/legacy/Staking/StakingCenter/StakingCenter.tsx", "start": { - "line": 131, + "line": 146, "column": 9, - "index": 4730 + "index": 5740 }, "end": { - "line": 134, + "line": 149, "column": 3, - "index": 4838 + "index": 5848 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!The data from the stake pool(s) you selected is invalid. Please try again", "file": "src/legacy/Staking/StakingCenter/StakingCenter.tsx", "start": { - "line": 135, + "line": 150, "column": 11, - "index": 4851 + "index": 5861 }, "end": { - "line": 138, + "line": 153, "column": 3, - "index": 5017 + "index": 6027 } } ] \ No newline at end of file From 4a84fc7819bff82ffc3fcf27385ec739fa514e30 Mon Sep 17 00:00:00 2001 From: Javier Bueno Date: Fri, 18 Oct 2024 18:08:56 +0200 Subject: [PATCH 2/5] feature(wallet-mobile): new tx review for stake delegation --- .../ios/yoroi.xcodeproj/project.pbxproj | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj b/apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj index 9a42927d8f..2069522357 100644 --- a/apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj +++ b/apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj @@ -837,10 +837,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = yoroi/yoroi.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 610; - DEVELOPMENT_TEAM = F8NVT2G2L4; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = F8NVT2G2L4; ENABLE_BITCODE = NO; ENVFILE = "$(PODS_ROOT)/../../.env"; INFOPLIST_FILE = yoroi/Info.plist; @@ -863,6 +864,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.emurgo.yoroi; PRODUCT_NAME = yoroi; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.emurgo.yoroi"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; @@ -880,10 +882,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = yoroi/yoroi.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 610; - DEVELOPMENT_TEAM = F8NVT2G2L4; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = F8NVT2G2L4; ENVFILE = "$(PODS_ROOT)/../../.env.production"; INFOPLIST_FILE = yoroi/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Yoroi; @@ -905,6 +908,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.emurgo.yoroi; PRODUCT_NAME = yoroi; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.emurgo.yoroi"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; From 28bbd8fe82b036c952c83f33d89f57e2adf79519 Mon Sep 17 00:00:00 2001 From: Javier Bueno Date: Thu, 24 Oct 2024 13:38:58 +0200 Subject: [PATCH 3/5] feature(wallet-mobile): new tx review for withdraw staking rewards --- .../.storybook/storybook.requires.js | 1 - .../ReviewTx/common/ReviewTxProvider.tsx | 35 +- .../ReviewTx/common/hooks/useFormattedTx.tsx | 9 +- .../ReviewTx/common/hooks/useOnConfirm.tsx | 23 +- .../ReviewTx/common/hooks/useStrings.tsx | 15 + .../features/ReviewTx/common/operations.tsx | 109 ++++-- .../src/features/ReviewTx/common/types.ts | 63 +++- .../ReviewTxScreen/Overview/OverviewTab.tsx | 15 +- .../ReviewTxScreen/ReviewTxScreen.tsx | 2 +- .../Staking/Governance/common/helpers.tsx | 35 +- .../Governance/useCases/Home/HomeScreen.tsx | 3 - .../src/kernel/i18n/locales/en-US.json | 3 + .../WithdrawStakingRewards.tsx | 28 +- .../PoolTransition/usePoolTransition.tsx | 5 +- .../Staking/StakingCenter/StakingCenter.tsx | 11 +- .../src/yoroi-wallets/hooks/index.ts | 19 ++ .../ReviewTx/common/hooks/useStrings.json | 309 ++++++++++-------- .../ListAmountsToSendScreen.json | 4 +- .../WithdrawStakingRewards.json | 72 ++-- .../PoolTransition/usePoolTransition.json | 104 +++--- .../Staking/StakingCenter/StakingCenter.json | 16 +- 21 files changed, 530 insertions(+), 351 deletions(-) diff --git a/apps/wallet-mobile/.storybook/storybook.requires.js b/apps/wallet-mobile/.storybook/storybook.requires.js index 6ec961a8f2..efdffe4715 100644 --- a/apps/wallet-mobile/.storybook/storybook.requires.js +++ b/apps/wallet-mobile/.storybook/storybook.requires.js @@ -283,7 +283,6 @@ const getStories = () => { "./src/legacy/HW/LedgerConnect/DeviceItem/DeviceItem.stories.tsx": require("../src/legacy/HW/LedgerConnect/DeviceItem/DeviceItem.stories.tsx"), "./src/legacy/HW/LedgerConnect/LedgerConnect.stories.tsx": require("../src/legacy/HW/LedgerConnect/LedgerConnect.stories.tsx"), "./src/legacy/HW/LedgerTransportSwitchModal/LedgerTransportSwitchModal.stories.tsx": require("../src/legacy/HW/LedgerTransportSwitchModal/LedgerTransportSwitchModal.stories.tsx"), - "./src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.stories.tsx": require("../src/legacy/Staking/DelegationConfirmation/DelegationConfirmation.stories.tsx"), "./src/legacy/Staking/FailedTx/FailedTxScreen.stories.tsx": require("../src/legacy/Staking/FailedTx/FailedTxScreen.stories.tsx"), "./src/legacy/Staking/PoolDetails/PoolDetailScreen.stories.tsx": require("../src/legacy/Staking/PoolDetails/PoolDetailScreen.stories.tsx"), "./src/legacy/Staking/PoolTransition/PoolTransitionModal.stories.tsx": require("../src/legacy/Staking/PoolTransition/PoolTransitionModal.stories.tsx"), diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/ReviewTxProvider.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/ReviewTxProvider.tsx index 44274bd96c..c882fef6e7 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/ReviewTxProvider.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/ReviewTxProvider.tsx @@ -31,9 +31,10 @@ export const ReviewTxProvider = ({ dispatch({type: ReviewTxActionType.OnSuccessChanged, onSuccess}), onErrorChanged: (onError: ReviewTxState['onError']) => dispatch({type: ReviewTxActionType.OnErrorChanged, onError}), onNotSupportedCIP1694Changed: (onNotSupportedCIP1694: ReviewTxState['onNotSupportedCIP1694']) => - dispatch({type: ReviewTxActionType.onNotSupportedCIP1694Changed, onNotSupportedCIP1694}), + dispatch({type: ReviewTxActionType.OnNotSupportedCIP1694Changed, onNotSupportedCIP1694}), onCIP36SupportChangeChanged: (onCIP36SupportChange: ReviewTxState['onCIP36SupportChange']) => - dispatch({type: ReviewTxActionType.onCIP36SupportChangeChanged, onCIP36SupportChange}), + dispatch({type: ReviewTxActionType.OnCIP36SupportChangeChanged, onCIP36SupportChange}), + reset: () => dispatch({type: ReviewTxActionType.Reset}), }).current const context = React.useMemo( @@ -78,14 +79,26 @@ const reviewTxReducer = (state: ReviewTxState, action: ReviewTxAction) => { draft.onError = action.onError break - case ReviewTxActionType.onNotSupportedCIP1694Changed: + case ReviewTxActionType.OnNotSupportedCIP1694Changed: draft.onNotSupportedCIP1694 = action.onNotSupportedCIP1694 break - case ReviewTxActionType.onCIP36SupportChangeChanged: + case ReviewTxActionType.OnCIP36SupportChangeChanged: draft.onCIP36SupportChange = action.onCIP36SupportChange break + case ReviewTxActionType.Reset: + draft.unsignedTx = castDraft(defaultState.unsignedTx) + draft.cbor = defaultState.cbor + draft.operations = defaultState.operations + draft.customReceiverTitle = defaultState.customReceiverTitle + draft.details = defaultState.details + draft.onSuccess = defaultState.onSuccess + draft.onError = defaultState.onError + draft.onNotSupportedCIP1694 = defaultState.onNotSupportedCIP1694 + draft.onCIP36SupportChange = defaultState.onCIP36SupportChange + break + default: throw new Error('[ReviewTxContext] invalid action') } @@ -122,13 +135,16 @@ type ReviewTxAction = onError: ReviewTxState['onError'] } | { - type: ReviewTxActionType.onNotSupportedCIP1694Changed + type: ReviewTxActionType.OnNotSupportedCIP1694Changed onNotSupportedCIP1694: ReviewTxState['onNotSupportedCIP1694'] } | { - type: ReviewTxActionType.onCIP36SupportChangeChanged + type: ReviewTxActionType.OnCIP36SupportChangeChanged onCIP36SupportChange: ReviewTxState['onCIP36SupportChange'] } + | { + type: ReviewTxActionType.Reset + } export type ReviewTxState = { unsignedTx: YoroiUnsignedTx | null @@ -152,6 +168,7 @@ type ReviewTxActions = { onErrorChanged: (onError: ReviewTxState['onError']) => void onNotSupportedCIP1694Changed: (onNotSupportedCIP1694: ReviewTxState['onNotSupportedCIP1694']) => void onCIP36SupportChangeChanged: (onCIP36SupportChange: ReviewTxState['onCIP36SupportChange']) => void + reset: () => void } const defaultState: ReviewTxState = Object.freeze({ @@ -181,6 +198,7 @@ const initialReviewTxContext: ReviewTxContext = { onErrorChanged: missingInit, onNotSupportedCIP1694Changed: missingInit, onCIP36SupportChangeChanged: missingInit, + reset: missingInit, } enum ReviewTxActionType { @@ -191,8 +209,9 @@ enum ReviewTxActionType { DetailsChanged = 'detailsChanged', OnSuccessChanged = 'onSuccessChanged', OnErrorChanged = 'onErrorChanged', - onNotSupportedCIP1694Changed = 'onNotSupportedCIP1694Changed', - onCIP36SupportChangeChanged = 'onCIP36SupportChangeChanged', + OnNotSupportedCIP1694Changed = 'onNotSupportedCIP1694Changed', + OnCIP36SupportChangeChanged = 'onCIP36SupportChangeChanged', + Reset = 'reset', } type ReviewTxContext = ReviewTxState & ReviewTxActions diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx index e01bdae3ea..419c218b1c 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx @@ -14,6 +14,8 @@ import {asQuantity} from '../../../../yoroi-wallets/utils/utils' import {usePortfolioTokenInfos} from '../../../Portfolio/common/hooks/usePortfolioTokenInfos' import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet' import { + Certificates, + FormattedCertificates, FormattedFee, FormattedInputs, FormattedOutputs, @@ -50,12 +52,13 @@ export const useFormattedTx = (data: TransactionBody): FormattedTx => { const formattedInputs = useFormattedInputs(wallet, inputs, portfolioTokenInfos) const formattedOutputs = useFormattedOutputs(wallet, outputs, portfolioTokenInfos) const formattedFee = formatFee(wallet, data) + const formattedCertificates = formatCertificates(data.certs as Certificates) return { inputs: formattedInputs, outputs: formattedOutputs, fee: formattedFee, - certificates: data.certs ?? null, + certificates: formattedCertificates, } } @@ -220,6 +223,10 @@ export const formatFee = (wallet: YoroiWallet, data: TransactionBody): Formatted } } +const formatCertificates = (certificates: Certificates) => { + return certificates.flatMap(Object.entries) as FormattedCertificates +} + const deriveAddress = async (address: string, chainId: number) => { try { return await deriveRewardAddressFromAddress(address, chainId) diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useOnConfirm.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useOnConfirm.tsx index b00d30458b..129affceba 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useOnConfirm.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useOnConfirm.tsx @@ -6,6 +6,7 @@ import {ConfirmTxWithSpendingPasswordModal} from '../../../../components/Confirm import {useModal} from '../../../../components/Modal/ModalContext' import {YoroiSignedTx, YoroiUnsignedTx} from '../../../../yoroi-wallets/types/yoroi' import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet' +import {useReviewTx} from '../ReviewTxProvider' import {useStrings} from './useStrings' // TODO: make it compatible with CBOR signing @@ -28,6 +29,16 @@ export const useOnConfirm = ({ const {meta} = useSelectedWallet() const {openModal, closeModal} = useModal() const strings = useStrings() + const {reset} = useReviewTx() + + const handleOnSuccess = (signedTx: YoroiSignedTx) => { + onSuccess?.(signedTx) + reset() + } + const handleOnError = () => { + onError?.() + reset() + } const onConfirm = () => { if (meta.isHW) { @@ -36,7 +47,7 @@ export const useOnConfirm = ({ onSuccess?.(signedTx)} + onSuccess={handleOnSuccess} onNotSupportedCIP1694={() => { if (onNotSupportedCIP1694) { closeModal() @@ -55,8 +66,8 @@ export const useOnConfirm = ({ strings.signTransaction, onSuccess?.(signedTx)} - onError={onError ?? undefined} + onSuccess={handleOnSuccess} + onError={handleOnError} />, ) return @@ -65,11 +76,7 @@ export const useOnConfirm = ({ if (!meta.isHW && meta.isEasyConfirmationEnabled) { openModal( strings.signTransaction, - onSuccess?.(signedTx)} - onError={onError ?? undefined} - />, + , ) return } diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx index 3858509fab..59311a3c62 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useStrings.tsx @@ -40,6 +40,9 @@ export const useStrings = () => { selectNoConfidence: intl.formatMessage(messages.selectNoConfidence), delegateVotingToDRep: intl.formatMessage(messages.delegateVotingToDRep), delegateStake: intl.formatMessage(messages.delegateStake), + deregisterStakingKey: intl.formatMessage(messages.deregisterStakingKey), + rewardsWithdrawalLabel: intl.formatMessage(messages.rewardsWithdrawalLabel), + rewardsWithdrawalText: intl.formatMessage(messages.rewardsWithdrawalText), } } @@ -160,6 +163,18 @@ const messages = defineMessages({ id: 'txReview.operations.registerStakingKey', defaultMessage: '!!!Register staking key deposit', }, + deregisterStakingKey: { + id: 'txReview.operations.deregisterStakingKey', + defaultMessage: '!!!Deregister staking key', + }, + rewardsWithdrawalLabel: { + id: 'txReview.operations.rewardsWithdrawal.label', + defaultMessage: '!!!Staking', + }, + rewardsWithdrawalText: { + id: 'txReview.operations.rewardsWithdrawal.text', + defaultMessage: '!!!Rewards withdrawal', + }, selectAbstain: { id: 'txReview.operations.selectAbstain', defaultMessage: '!!!Select abstain', diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx index 37e67650b2..6af35e8f63 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx @@ -1,5 +1,3 @@ -import {PoolInfoApi} from '@emurgo/yoroi-lib' -import {useBech32DRepID} from '@yoroi/staking' import {useTheme} from '@yoroi/theme' import * as React from 'react' import {Linking, StyleSheet, Text, View} from 'react-native' @@ -7,14 +5,16 @@ import {TouchableOpacity} from 'react-native-gesture-handler' import {useQuery} from 'react-query' import {Space} from '../../../components/Space/Space' -import {getPoolBech32Id} from '../../../yoroi-wallets/cardano/delegationUtils' +import {wrappedCsl} from '../../../yoroi-wallets/cardano/wrappedCsl' +import {usePoolInfo} from '../../../yoroi-wallets/hooks' import {formatTokenWithText} from '../../../yoroi-wallets/utils/format' import {asQuantity} from '../../../yoroi-wallets/utils/utils' import {useSelectedNetwork} from '../../WalletManager/common/hooks/useSelectedNetwork' import {useSelectedWallet} from '../../WalletManager/common/hooks/useSelectedWallet' import {useStrings} from './hooks/useStrings' +import {Certificate, CertificateTypes, FormattedCertificates} from './types' -export const RegisterStakingKeyOperation = () => { +export const StakeRegistrationOperation = () => { const {styles} = useStyles() const strings = useStrings() const {wallet} = useSelectedWallet() @@ -31,7 +31,32 @@ export const RegisterStakingKeyOperation = () => { ) } -export const DelegateStakeOperation = ({poolId}: {poolId: string}) => { + +export const StakeDeregistrationOperation = () => { + const {styles} = useStyles() + const strings = useStrings() + + return ( + + {strings.deregisterStakingKey} + + ) +} + +export const StakeRewardsWithdrawalOperation = () => { + const {styles} = useStyles() + const strings = useStrings() + + return ( + + {strings.rewardsWithdrawalLabel} + + {strings.rewardsWithdrawalText} + + ) +} + +export const StakeDelegateOperation = ({poolId}: {poolId: string}) => { const {styles} = useStyles() const strings = useStrings() const poolInfo = usePoolInfo({poolId}) @@ -55,23 +80,6 @@ export const DelegateStakeOperation = ({poolId}: {poolId: string}) => { ) } -export const usePoolInfo = ({poolId}: {poolId: string}) => { - const {networkManager} = useSelectedNetwork() - const poolInfoApi = React.useMemo( - () => new PoolInfoApi(networkManager.legacyApiBaseUrl), - [networkManager.legacyApiBaseUrl], - ) - const poolInfo = useQuery({ - queryKey: ['usePoolInfoStakeOperation', poolId], - queryFn: async () => { - const poolBech32Id = await getPoolBech32Id(poolId) - return poolInfoApi.getSingleExplorerPoolInfo(poolBech32Id) - }, - }) - - return poolInfo?.data ?? null -} - export const AbstainOperation = () => { const {styles} = useStyles() const strings = useStrings() @@ -94,11 +102,11 @@ export const NoConfidenceOperation = () => { ) } -export const DelegateVotingToDrepOperation = ({drepID}: {drepID: string}) => { +export const VoteDelegationOperation = ({drepID}: {drepID: string}) => { const {styles} = useStyles() const strings = useStrings() - const {data: bech32DrepId} = useBech32DRepID(drepID) + const bech32DrepId = useDrepBech32Id(drepID) return ( @@ -111,6 +119,59 @@ export const DelegateVotingToDrepOperation = ({drepID}: {drepID: string}) => { ) } +export const useOperations = (certificates: FormattedCertificates | null) => { + if (certificates === null) return [] + + return certificates.reduce((acc, [certificateKind, CertificateData], index) => { + switch (certificateKind) { + case CertificateTypes.StakeRegistration: + return [...acc, ] + + case CertificateTypes.StakeDeregistration: + return [...acc, ] + + case CertificateTypes.StakeDelegation: { + const poolKeyHash = (CertificateData as Certificate[CertificateTypes.StakeDelegation]).pool_keyhash ?? null + if (poolKeyHash == null) return acc + return [...acc, ] + } + + case CertificateTypes.VoteDelegation: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const drep: any = (CertificateData as Certificate[CertificateTypes.VoteDelegation]).drep + + if (drep === 'AlwaysAbstain') return [...acc, ] + if (drep === 'AlwaysNoConfidence') return [...acc, ] + + const drepId = drep.KeyHash ?? drep.ScriptHash ?? '' + return [...acc, ] + } + + default: + return acc + } + }, []) +} + +export const getDrepBech32Id = async (poolId: string) => { + const {csl, release} = wrappedCsl() + try { + const keyHash = await csl.Ed25519KeyHash.fromHex(poolId) + return keyHash.toBech32('drep') + } finally { + release() + } +} + +export const useDrepBech32Id = (poolId: string) => { + const query = useQuery({ + queryKey: ['drepBech32', poolId], + queryFn: () => getDrepBech32Id(poolId), + }) + + return query?.data ?? null +} + const useStyles = () => { const {color, atoms} = useTheme() diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/types.ts b/apps/wallet-mobile/src/features/ReviewTx/common/types.ts index f06f1d2530..95d7a4ce05 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/types.ts +++ b/apps/wallet-mobile/src/features/ReviewTx/common/types.ts @@ -1,8 +1,24 @@ import { - CertificatesJSON, + CommitteeColdResignJSON, + CommitteeHotAuthJSON, + DRepDeregistrationJSON, + DRepRegistrationJSON, + DRepUpdateJSON, + GenesisKeyDelegationJSON, + MoveInstantaneousRewardsCertJSON, + PoolRegistrationJSON, + PoolRetirementJSON, + StakeAndVoteDelegationJSON, + StakeDelegationJSON, + StakeDeregistrationJSON, + StakeRegistrationAndDelegationJSON, + StakeRegistrationJSON, + StakeVoteRegistrationAndDelegationJSON, TransactionBodyJSON, TransactionInputsJSON, TransactionOutputsJSON, + VoteDelegationJSON, + VoteRegistrationAndDelegationJSON, } from '@emurgo/cardano-serialization-lib-nodejs' import {CredKind} from '@emurgo/cross-csl-core' import {Balance, Portfolio} from '@yoroi/types' @@ -57,7 +73,7 @@ export type FormattedTx = { inputs: FormattedInputs outputs: FormattedOutputs fee: FormattedFee - certificates: Certificates + certificates: FormattedCertificates | null } export type FormattedMetadata = { @@ -65,4 +81,45 @@ export type FormattedMetadata = { metadata: {msg: Array} | null } -export type Certificates = CertificatesJSON | null +export type Certificates = Array +export type FormattedCertificates = Array<[CertificateTypes, Certificate[CertificateTypes]]> + +export type Certificate = { + StakeRegistration: StakeRegistrationJSON + StakeDeregistration: StakeDeregistrationJSON + StakeDelegation: StakeDelegationJSON + PoolRegistration: PoolRegistrationJSON + PoolRetirement: PoolRetirementJSON + GenesisKeyDelegation: GenesisKeyDelegationJSON + MoveInstantaneousRewardsCert: MoveInstantaneousRewardsCertJSON + CommitteeHotAuth: CommitteeHotAuthJSON + CommitteeColdResign: CommitteeColdResignJSON + DRepDeregistration: DRepDeregistrationJSON + DRepRegistration: DRepRegistrationJSON + DRepUpdate: DRepUpdateJSON + StakeAndVoteDelegation: StakeAndVoteDelegationJSON + StakeRegistrationAndDelegation: StakeRegistrationAndDelegationJSON + StakeVoteRegistrationAndDelegation: StakeVoteRegistrationAndDelegationJSON + VoteDelegation: VoteDelegationJSON + VoteRegistrationAndDelegation: VoteRegistrationAndDelegationJSON +} + +export enum CertificateTypes { + StakeRegistration = 'StakeRegistration', + StakeDeregistration = 'StakeDeregistration', + StakeDelegation = 'StakeDelegation', + PoolRegistration = 'PoolRegistration', + PoolRetirement = 'PoolRetirement', + GenesisKeyDelegation = 'GenesisKeyDelegation', + MoveInstantaneousRewardsCert = 'MoveInstantaneousRewardsCert', + CommitteeHotAuth = 'CommitteeHotAuth', + CommitteeColdResign = 'CommitteeColdResign', + DRepDeregistration = 'DRepDeregistration', + DRepRegistration = 'DRepRegistration', + DRepUpdate = 'DRepUpdate', + StakeAndVoteDelegation = 'StakeAndVoteDelegation', + StakeRegistrationAndDelegation = 'StakeRegistrationAndDelegation', + StakeVoteRegistrationAndDelegation = 'StakeVoteRegistrationAndDelegation', + VoteDelegation = 'VoteDelegation', + VoteRegistrationAndDelegation = 'VoteRegistrationAndDelegation', +} 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 index cd04aeeb68..640a2783eb 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/Overview/OverviewTab.tsx @@ -17,17 +17,18 @@ import {useWalletManager} from '../../../../WalletManager/context/WalletManagerP import {Accordion} from '../../../common/Accordion' import {CopiableText} from '../../../common/CopiableText' import {useStrings} from '../../../common/hooks/useStrings' +import {useOperations} from '../../../common/operations' import {ReviewTxState, useReviewTx} from '../../../common/ReviewTxProvider' import {TokenItem} from '../../../common/TokenItem' import {FormattedOutputs, FormattedTx} from '../../../common/types' export const OverviewTab = ({ tx, - operations, + extraOperations, details, }: { tx: FormattedTx - operations: ReviewTxState['operations'] + extraOperations: ReviewTxState['operations'] details: ReviewTxState['details'] }) => { const {styles} = useStyles() @@ -45,7 +46,7 @@ export const OverviewTab = ({ - +
@@ -212,8 +213,10 @@ const ReceiverSection = ({notOwnedOutputs}: {notOwnedOutputs: FormattedOutputs}) ) } -const OperationsSection = ({operations}: {operations: ReviewTxState['operations']}) => { - if (operations === null || (Array.isArray(operations) && operations.length === 0)) return null +const OperationsSection = ({tx, extraOperations}: {tx: FormattedTx; extraOperations: ReviewTxState['operations']}) => { + const operations = useOperations(tx.certificates) + + if (extraOperations === null && tx.certificates === null) return null return ( @@ -222,7 +225,7 @@ const OperationsSection = ({operations}: {operations: ReviewTxState['operations' - {operations.map((operation, index) => { + {[...operations, ...(extraOperations ?? [])].map((operation, index) => { if (index === 0) return operation return ( diff --git a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx index 48f54294af..1b3344465d 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/useCases/ReviewTxScreen/ReviewTxScreen.tsx @@ -64,7 +64,7 @@ export const ReviewTxScreen = () => { {() => ( /* TODO: make scrollview general to use button border */ - + )} diff --git a/apps/wallet-mobile/src/features/Staking/Governance/common/helpers.tsx b/apps/wallet-mobile/src/features/Staking/Governance/common/helpers.tsx index b8ec96328e..500b7e42c5 100644 --- a/apps/wallet-mobile/src/features/Staking/Governance/common/helpers.tsx +++ b/apps/wallet-mobile/src/features/Staking/Governance/common/helpers.tsx @@ -3,8 +3,6 @@ import { type StakingKeyState, governanceApiMaker, governanceManagerMaker, - GovernanceProvider, - useGovernance, useStakingKeyState, useUpdateLatestGovernanceAction, } from '@yoroi/staking' @@ -16,12 +14,6 @@ import {YoroiWallet} from '../../../../yoroi-wallets/cardano/types' import {useStakingKey} from '../../../../yoroi-wallets/hooks' import {YoroiUnsignedTx} from '../../../../yoroi-wallets/types/yoroi' import {CardanoMobile} from '../../../../yoroi-wallets/wallets' -import { - AbstainOperation, - DelegateVotingToDrepOperation, - NoConfidenceOperation, - RegisterStakingKeyOperation, -} from '../../../ReviewTx/common/operations' import {useReviewTx} from '../../../ReviewTx/common/ReviewTxProvider' import {useBestBlock} from '../../../WalletManager/common/hooks/useBestBlock' import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet' @@ -78,34 +70,21 @@ export const useGovernanceManagerMaker = () => { } export const useGovernanceActions = () => { - const {manager} = useGovernance() const {wallet} = useSelectedWallet() const navigateTo = useNavigateTo() - const {unsignedTxChanged, onSuccessChanged, onErrorChanged, operationsChanged, onNotSupportedCIP1694Changed} = - useReviewTx() + const {unsignedTxChanged, onSuccessChanged, onErrorChanged, onNotSupportedCIP1694Changed} = useReviewTx() const {updateLatestGovernanceAction} = useUpdateLatestGovernanceAction(wallet.id) const {navigateToTxReview} = useWalletNavigation() const handleDelegateAction = ({ drepID, unsignedTx, - hasStakeCert = false, navigateToStakingOnSuccess = false, }: { drepID: string unsignedTx: YoroiUnsignedTx - hasStakeCert?: boolean navigateToStakingOnSuccess?: boolean }) => { - let operations = [ - - - , - ] - - if (hasStakeCert) operations = [, ...operations] - - operationsChanged(operations) onSuccessChanged((signedTx) => { updateLatestGovernanceAction({kind: 'delegate-to-drep', drepID, txID: signedTx.signedTx.id}) navigateTo.txSuccess({navigateToStaking: navigateToStakingOnSuccess ?? false, kind: 'delegate'}) @@ -121,17 +100,11 @@ export const useGovernanceActions = () => { const handleAbstainAction = ({ unsignedTx, - hasStakeCert = false, navigateToStakingOnSuccess = false, }: { unsignedTx: YoroiUnsignedTx - hasStakeCert?: boolean navigateToStakingOnSuccess?: boolean }) => { - let operations = [] - if (hasStakeCert) operations = [, ...operations] - - operationsChanged(operations) onSuccessChanged((signedTx) => { updateLatestGovernanceAction({kind: 'vote', vote: 'abstain', txID: signedTx.signedTx.id}) navigateTo.txSuccess({navigateToStaking: navigateToStakingOnSuccess ?? false, kind: 'abstain'}) @@ -147,17 +120,11 @@ export const useGovernanceActions = () => { const handleNoConfidenceAction = ({ unsignedTx, - hasStakeCert = false, navigateToStakingOnSuccess = false, }: { unsignedTx: YoroiUnsignedTx - hasStakeCert?: boolean navigateToStakingOnSuccess?: boolean }) => { - let operations = [] - if (hasStakeCert) operations = [, ...operations] - - operationsChanged(operations) onSuccessChanged((signedTx) => { updateLatestGovernanceAction({kind: 'vote', vote: 'no-confidence', txID: signedTx.signedTx.id}) navigateTo.txSuccess({ diff --git a/apps/wallet-mobile/src/features/Staking/Governance/useCases/Home/HomeScreen.tsx b/apps/wallet-mobile/src/features/Staking/Governance/useCases/Home/HomeScreen.tsx index 9f43088d3e..19f03a4fcf 100644 --- a/apps/wallet-mobile/src/features/Staking/Governance/useCases/Home/HomeScreen.tsx +++ b/apps/wallet-mobile/src/features/Staking/Governance/useCases/Home/HomeScreen.tsx @@ -255,7 +255,6 @@ const NeverParticipatedInGovernanceVariant = () => { unsignedTx, drepID, navigateToStakingOnSuccess: params?.navigateToStakingOnSuccess, - hasStakeCert: stakeCert !== null, }) }, }, @@ -281,7 +280,6 @@ const NeverParticipatedInGovernanceVariant = () => { governanceActions.handleAbstainAction({ unsignedTx, navigateToStakingOnSuccess: params?.navigateToStakingOnSuccess, - hasStakeCert: stakeCert !== null, }) }, }, @@ -306,7 +304,6 @@ const NeverParticipatedInGovernanceVariant = () => { governanceActions.handleNoConfidenceAction({ unsignedTx, navigateToStakingOnSuccess: params?.navigateToStakingOnSuccess, - hasStakeCert: stakeCert !== null, }) }, }, diff --git a/apps/wallet-mobile/src/kernel/i18n/locales/en-US.json b/apps/wallet-mobile/src/kernel/i18n/locales/en-US.json index caeffe72a9..56f0b8cc98 100644 --- a/apps/wallet-mobile/src/kernel/i18n/locales/en-US.json +++ b/apps/wallet-mobile/src/kernel/i18n/locales/en-US.json @@ -1248,6 +1248,9 @@ "txReview.tokenDetails.overViewTab.details.label": "Details on", "txReview.tokenDetails.title": "Asset Details", "txReview.operations.registerStakingKey": "Register staking key deposit", + "txReview.operations.deregisterStakingKey": "Deregister staking key", + "txReview.operations.rewardsWithdrawal.label": "Staking", + "txReview.operations.rewardsWithdrawal.text": "Rewards withdrawal", "txReview.operations.selectAbstain": "Select abstain", "txReview.operations.selectNoConfidence": "Select no confidence", "txReview.operations.delegateVotingToDRep": "Delegate voting to", diff --git a/apps/wallet-mobile/src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx b/apps/wallet-mobile/src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx index c85860ddd7..18e000913d 100644 --- a/apps/wallet-mobile/src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx +++ b/apps/wallet-mobile/src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx @@ -11,42 +11,32 @@ import {PleaseWaitView} from '../../../components/PleaseWaitModal' import {ScrollView, useScrollView} from '../../../components/ScrollView/ScrollView' import {Space} from '../../../components/Space/Space' import {Warning} from '../../../components/Warning/Warning' +import {StakeRewardsWithdrawalOperation} from '../../../features/ReviewTx/common/operations' +import {useReviewTx} from '../../../features/ReviewTx/common/ReviewTxProvider' import {useSelectedWallet} from '../../../features/WalletManager/common/hooks/useSelectedWallet' import globalMessages, {confirmationMessages, ledgerMessages, txLabels} from '../../../kernel/i18n/global-messages' import {useWalletNavigation} from '../../../kernel/navigation' import {YoroiWallet} from '../../../yoroi-wallets/cardano/types' import {useWithdrawalTx} from '../../../yoroi-wallets/hooks' import {YoroiUnsignedTx} from '../../../yoroi-wallets/types/yoroi' -import {delay} from '../../../yoroi-wallets/utils/timeUtils' import {Quantities} from '../../../yoroi-wallets/utils/utils' import {useStakingInfo} from '../StakePoolInfos' -import {ConfirmTx} from './ConfirmTx/ConfirmTx' type Props = { wallet: YoroiWallet } export const WithdrawStakingRewards = ({wallet}: Props) => { const strings = useWithdrawStakingRewardsStrings() - const {closeModal, openModal} = useModal() - const {resetToTxHistory} = useWalletNavigation() + const {closeModal} = useModal() + const {navigateToTxReview} = useWalletNavigation() + const {unsignedTxChanged, operationsChanged} = useReviewTx() - const handleOnConfirm = async (withdrawalTx: YoroiUnsignedTx) => { + const handleOnConfirm = (withdrawalTx: YoroiUnsignedTx) => { closeModal() - await delay(1000) - - openModal( - strings.confirmTx, - - resetToTxHistory()} - onCancel={() => closeModal()} - /> - , - 450, - ) + unsignedTxChanged(withdrawalTx) + operationsChanged([]) + navigateToTxReview() } return ( diff --git a/apps/wallet-mobile/src/legacy/Staking/PoolTransition/usePoolTransition.tsx b/apps/wallet-mobile/src/legacy/Staking/PoolTransition/usePoolTransition.tsx index d6bd535031..e4dd55e330 100644 --- a/apps/wallet-mobile/src/legacy/Staking/PoolTransition/usePoolTransition.tsx +++ b/apps/wallet-mobile/src/legacy/Staking/PoolTransition/usePoolTransition.tsx @@ -7,7 +7,6 @@ import * as React from 'react' import {defineMessages, useIntl} from 'react-intl' import {useQuery} from 'react-query' -import {DelegateStakeOperation} from '../../../features/ReviewTx/common/operations' import {useReviewTx} from '../../../features/ReviewTx/common/ReviewTxProvider' import {useSelectedNetwork} from '../../../features/WalletManager/common/hooks/useSelectedNetwork' import {useSelectedWallet} from '../../../features/WalletManager/common/hooks/useSelectedWallet' @@ -41,7 +40,7 @@ export const usePoolTransition = () => { const {wallet, meta} = useSelectedWallet() const {networkManager} = useSelectedNetwork() const {navigateToTxReview, resetToTxHistory} = useWalletNavigation() - const {unsignedTxChanged, onSuccessChanged, onErrorChanged, operationsChanged} = useReviewTx() + const {unsignedTxChanged, onSuccessChanged, onErrorChanged} = useReviewTx() const {stakingInfo, isLoading} = useStakingInfo(wallet) const poolInfoApi = React.useMemo( () => new PoolInfoApi(networkManager.legacyApiBaseUrl), @@ -65,7 +64,6 @@ export const usePoolTransition = () => { const navigateToUpdate = React.useCallback(async () => { try { const yoroiUnsignedTx = await createDelegationTx(wallet, poolId, meta) - operationsChanged([]) unsignedTxChanged(yoroiUnsignedTx) onSuccessChanged(() => { resetToTxHistory() @@ -85,7 +83,6 @@ export const usePoolTransition = () => { wallet, poolId, meta, - operationsChanged, unsignedTxChanged, onSuccessChanged, onErrorChanged, diff --git a/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx b/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx index 425290317f..2986550471 100644 --- a/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx +++ b/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx @@ -9,7 +9,6 @@ import {useQueryClient} from 'react-query' import {PleaseWaitModal} from '../../../components/PleaseWaitModal' import {Spacer} from '../../../components/Spacer/Spacer' -import {DelegateStakeOperation, RegisterStakingKeyOperation} from '../../../features/ReviewTx/common/operations' import {useReviewTx} from '../../../features/ReviewTx/common/ReviewTxProvider' import {useSelectedWallet} from '../../../features/WalletManager/common/hooks/useSelectedWallet' import {useWalletManager} from '../../../features/WalletManager/context/WalletManagerProvider' @@ -20,7 +19,7 @@ import {logger} from '../../../kernel/logger/logger' import {useMetrics} from '../../../kernel/metrics/metricsManager' import {StakingCenterRouteNavigation, useWalletNavigation} from '../../../kernel/navigation' import {NotEnoughMoneyToSendError} from '../../../yoroi-wallets/cardano/types' -import {useStakingInfo, useStakingTx} from '../../Dashboard/StakePoolInfos' +import {useStakingTx} from '../../Dashboard/StakePoolInfos' import {PoolDetailScreen} from '../PoolDetails' export const StakingCenter = () => { @@ -36,9 +35,7 @@ export const StakingCenter = () => { const {track} = useMetrics() const {plate} = walletManager.checksum(wallet.publicKeyHex) const {navigateToTxReview, resetToTxHistory} = useWalletNavigation() - const {unsignedTxChanged, onSuccessChanged, onErrorChanged, operationsChanged} = useReviewTx() - const stakingInfo = useStakingInfo(wallet, {suspense: true}) - const hasStakingKeyRegistered = stakingInfo?.data?.status !== 'not-registered' + const {unsignedTxChanged, onSuccessChanged, onErrorChanged} = useReviewTx() useFocusEffect( React.useCallback(() => { @@ -57,10 +54,6 @@ export const StakingCenter = () => { onSuccess: (yoroiUnsignedTx) => { if (selectedPoolId == null) return - let operations = [] - if (!hasStakingKeyRegistered) operations = [, ...operations] - - operationsChanged(operations) unsignedTxChanged(yoroiUnsignedTx) onSuccessChanged(() => { queryClient.resetQueries([wallet.id, 'stakingInfo']) diff --git a/apps/wallet-mobile/src/yoroi-wallets/hooks/index.ts b/apps/wallet-mobile/src/yoroi-wallets/hooks/index.ts index 29dbd086a9..ce610714ec 100644 --- a/apps/wallet-mobile/src/yoroi-wallets/hooks/index.ts +++ b/apps/wallet-mobile/src/yoroi-wallets/hooks/index.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import {walletChecksum} from '@emurgo/cip4-js' import {Certificate} from '@emurgo/cross-csl-core' +import {PoolInfoApi} from '@emurgo/yoroi-lib' import AsyncStorage, {AsyncStorageStatic} from '@react-native-async-storage/async-storage' import {mountMMKVStorage, observableStorageMaker, parseBoolean, useMutationWithInvalidations} from '@yoroi/common' import {themeStorageMaker} from '@yoroi/theme' @@ -25,6 +26,7 @@ import {isDev, isNightly} from '../../kernel/env' import {logger} from '../../kernel/logger/logger' import {deriveAddressFromXPub} from '../cardano/account-manager/derive-address-from-xpub' import {getSpendingKey, getStakingKey} from '../cardano/addressInfo/addressInfo' +import {getPoolBech32Id} from '../cardano/delegationUtils' import {WalletEvent, YoroiWallet} from '../cardano/types' import {TRANSACTION_DIRECTION, TRANSACTION_STATUS, TxSubmissionStatus} from '../types/other' import {YoroiSignedTx, YoroiUnsignedTx} from '../types/yoroi' @@ -702,3 +704,20 @@ export const useThemeStorageMaker = () => { return themeStorage } + +export const usePoolInfo = ({poolId}: {poolId: string}) => { + const {networkManager} = useSelectedNetwork() + const poolInfoApi = React.useMemo( + () => new PoolInfoApi(networkManager.legacyApiBaseUrl), + [networkManager.legacyApiBaseUrl], + ) + const poolInfo = useQuery({ + queryKey: ['usePoolInfoStakeOperation', poolId], + queryFn: async () => { + const poolBech32Id = await getPoolBech32Id(poolId) + return poolInfoApi.getSingleExplorerPoolInfo(poolBech32Id) + }, + }) + + return poolInfo?.data ?? null +} 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 index 9e1a48b052..63f5ba1400 100644 --- 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 @@ -4,14 +4,14 @@ "defaultMessage": "!!!Confirm", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 47, + "line": 50, "column": 11, - "index": 2325 + "index": 2562 }, "end": { - "line": 50, + "line": 53, "column": 3, - "index": 2392 + "index": 2629 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!UTxOs", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 51, + "line": 54, "column": 9, - "index": 2403 + "index": 2640 }, "end": { - "line": 54, + "line": 57, "column": 3, - "index": 2466 + "index": 2703 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!UTxOs", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 55, + "line": 58, "column": 12, - "index": 2480 + "index": 2717 }, "end": { - "line": 58, + "line": 61, "column": 3, - "index": 2552 + "index": 2789 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Overview", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 59, + "line": 62, "column": 15, - "index": 2569 + "index": 2806 }, "end": { - "line": 62, + "line": 65, "column": 3, - "index": 2647 + "index": 2884 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!!Metadata", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 63, + "line": 66, "column": 15, - "index": 2664 + "index": 2901 }, "end": { - "line": 66, + "line": 69, "column": 3, - "index": 2745 + "index": 2982 } }, { @@ -79,14 +79,14 @@ "defaultMessage": "!!!Metadata hash", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 67, + "line": 70, "column": 16, - "index": 2763 + "index": 3000 }, "end": { - "line": 70, + "line": 73, "column": 3, - "index": 2850 + "index": 3087 } }, { @@ -94,14 +94,14 @@ "defaultMessage": "!!!Metadata", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 71, + "line": 74, "column": 21, - "index": 2873 + "index": 3110 }, "end": { - "line": 74, + "line": 77, "column": 3, - "index": 2960 + "index": 3197 } }, { @@ -109,14 +109,14 @@ "defaultMessage": "!!!Wallet", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 75, + "line": 78, "column": 15, - "index": 2977 + "index": 3214 }, "end": { - "line": 78, + "line": 81, "column": 3, - "index": 3051 + "index": 3288 } }, { @@ -124,14 +124,14 @@ "defaultMessage": "!!!Fee", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 79, + "line": 82, "column": 12, - "index": 3065 + "index": 3302 }, "end": { - "line": 82, + "line": 85, "column": 3, - "index": 3124 + "index": 3361 } }, { @@ -139,14 +139,14 @@ "defaultMessage": "!!!Your Wallet", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 83, + "line": 86, "column": 17, - "index": 3143 + "index": 3380 }, "end": { - "line": 86, + "line": 89, "column": 3, - "index": 3229 + "index": 3466 } }, { @@ -154,14 +154,14 @@ "defaultMessage": "!!!Send", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 87, + "line": 90, "column": 13, - "index": 3244 + "index": 3481 }, "end": { - "line": 90, + "line": 93, "column": 3, - "index": 3319 + "index": 3556 } }, { @@ -169,14 +169,14 @@ "defaultMessage": "!!!To", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 91, + "line": 94, "column": 18, - "index": 3339 + "index": 3576 }, "end": { - "line": 94, + "line": 97, "column": 3, - "index": 3417 + "index": 3654 } }, { @@ -184,14 +184,14 @@ "defaultMessage": "!!!To script", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 95, + "line": 98, "column": 24, - "index": 3443 + "index": 3680 }, "end": { - "line": 98, + "line": 101, "column": 3, - "index": 3534 + "index": 3771 } }, { @@ -199,14 +199,14 @@ "defaultMessage": "!!!Inputs", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 99, + "line": 102, "column": 20, - "index": 3556 + "index": 3793 }, "end": { - "line": 102, + "line": 105, "column": 3, - "index": 3637 + "index": 3874 } }, { @@ -214,14 +214,14 @@ "defaultMessage": "!!!Outputs", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 103, + "line": 106, "column": 21, - "index": 3660 + "index": 3897 }, "end": { - "line": 106, + "line": 109, "column": 3, - "index": 3743 + "index": 3980 } }, { @@ -229,14 +229,14 @@ "defaultMessage": "!!!Your address", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 107, + "line": 110, "column": 25, - "index": 3770 + "index": 4007 }, "end": { - "line": 110, + "line": 113, "column": 3, - "index": 3862 + "index": 4099 } }, { @@ -244,14 +244,14 @@ "defaultMessage": "!!!Foreign address", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 111, + "line": 114, "column": 28, - "index": 3892 + "index": 4129 }, "end": { - "line": 114, + "line": 117, "column": 3, - "index": 3990 + "index": 4227 } }, { @@ -259,14 +259,14 @@ "defaultMessage": "!!!Overview", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 115, + "line": 118, "column": 12, - "index": 4004 + "index": 4241 }, "end": { - "line": 118, + "line": 121, "column": 3, - "index": 4095 + "index": 4332 } }, { @@ -274,14 +274,14 @@ "defaultMessage": "!!!JSON", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 119, + "line": 122, "column": 8, - "index": 4105 + "index": 4342 }, "end": { - "line": 122, + "line": 125, "column": 3, - "index": 4188 + "index": 4425 } }, { @@ -289,14 +289,14 @@ "defaultMessage": "!!!Metadata", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 123, + "line": 126, "column": 12, - "index": 4202 + "index": 4439 }, "end": { - "line": 126, + "line": 129, "column": 3, - "index": 4292 + "index": 4529 } }, { @@ -304,14 +304,14 @@ "defaultMessage": "!!!Policy ID", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 127, + "line": 130, "column": 12, - "index": 4306 + "index": 4543 }, "end": { - "line": 130, + "line": 133, "column": 3, - "index": 4395 + "index": 4632 } }, { @@ -319,14 +319,14 @@ "defaultMessage": "!!!Fingerprint", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 131, + "line": 134, "column": 15, - "index": 4412 + "index": 4649 }, "end": { - "line": 134, + "line": 137, "column": 3, - "index": 4506 + "index": 4743 } }, { @@ -334,14 +334,14 @@ "defaultMessage": "!!!Name", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 135, + "line": 138, "column": 8, - "index": 4516 + "index": 4753 }, "end": { - "line": 138, + "line": 141, "column": 3, - "index": 4608 + "index": 4845 } }, { @@ -349,14 +349,14 @@ "defaultMessage": "!!!Token Supply", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 139, + "line": 142, "column": 15, - "index": 4625 + "index": 4862 }, "end": { - "line": 142, + "line": 145, "column": 3, - "index": 4732 + "index": 4969 } }, { @@ -364,14 +364,14 @@ "defaultMessage": "!!!Symbol", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 143, + "line": 146, "column": 10, - "index": 4744 + "index": 4981 }, "end": { - "line": 146, + "line": 149, "column": 3, - "index": 4840 + "index": 5077 } }, { @@ -379,14 +379,14 @@ "defaultMessage": "!!!Description", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 147, + "line": 150, "column": 15, - "index": 4857 + "index": 5094 }, "end": { - "line": 150, + "line": 153, "column": 3, - "index": 4963 + "index": 5200 } }, { @@ -394,14 +394,14 @@ "defaultMessage": "!!!Details on", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 151, + "line": 154, "column": 11, - "index": 4976 + "index": 5213 }, "end": { - "line": 154, + "line": 157, "column": 3, - "index": 5077 + "index": 5314 } }, { @@ -409,14 +409,14 @@ "defaultMessage": "!!!Asset Details", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 155, + "line": 158, "column": 21, - "index": 5100 + "index": 5337 }, "end": { - "line": 158, + "line": 161, "column": 3, - "index": 5184 + "index": 5421 } }, { @@ -424,14 +424,59 @@ "defaultMessage": "!!!Register staking key deposit", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 159, + "line": 162, "column": 22, - "index": 5208 + "index": 5445 }, "end": { - "line": 162, + "line": 165, + "column": 3, + "index": 5555 + } + }, + { + "id": "txReview.operations.deregisterStakingKey", + "defaultMessage": "!!!Deregister staking key", + "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", + "start": { + "line": 166, + "column": 24, + "index": 5581 + }, + "end": { + "line": 169, "column": 3, - "index": 5318 + "index": 5687 + } + }, + { + "id": "txReview.operations.rewardsWithdrawal.label", + "defaultMessage": "!!!Staking", + "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", + "start": { + "line": 170, + "column": 26, + "index": 5715 + }, + "end": { + "line": 173, + "column": 3, + "index": 5809 + } + }, + { + "id": "txReview.operations.rewardsWithdrawal.text", + "defaultMessage": "!!!Rewards withdrawal", + "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", + "start": { + "line": 174, + "column": 25, + "index": 5836 + }, + "end": { + "line": 177, + "column": 3, + "index": 5940 } }, { @@ -439,14 +484,14 @@ "defaultMessage": "!!!Select abstain", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 163, + "line": 178, "column": 17, - "index": 5337 + "index": 5959 }, "end": { - "line": 166, + "line": 181, "column": 3, - "index": 5428 + "index": 6050 } }, { @@ -454,14 +499,14 @@ "defaultMessage": "!!!Select no confidence", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 167, + "line": 182, "column": 22, - "index": 5452 + "index": 6074 }, "end": { - "line": 170, + "line": 185, "column": 3, - "index": 5554 + "index": 6176 } }, { @@ -469,14 +514,14 @@ "defaultMessage": "!!!Delegate voting to", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 171, + "line": 186, "column": 24, - "index": 5580 + "index": 6202 }, "end": { - "line": 174, + "line": 189, "column": 3, - "index": 5682 + "index": 6304 } }, { @@ -484,14 +529,14 @@ "defaultMessage": "!!!Stake entire wallet balance to", "file": "src/features/ReviewTx/common/hooks/useStrings.tsx", "start": { - "line": 175, + "line": 190, "column": 17, - "index": 5701 + "index": 6323 }, "end": { - "line": 178, + "line": 193, "column": 3, - "index": 5808 + "index": 6430 } } ] \ 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 ce25e2fc6f..e786d91a44 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 @@ -6,12 +6,12 @@ "start": { "line": 219, "column": 12, - "index": 7280 + "index": 7301 }, "end": { "line": 222, "column": 3, - "index": 7357 + "index": 7378 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.json b/apps/wallet-mobile/translations/messages/src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.json index d0e1d39363..e34cf33ec5 100644 --- a/apps/wallet-mobile/translations/messages/src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.json +++ b/apps/wallet-mobile/translations/messages/src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Also deregister staking key?", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 166, + "line": 156, "column": 21, - "index": 6114 + "index": 6060 }, "end": { - "line": 169, + "line": 159, "column": 3, - "index": 6242 + "index": 6188 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!When withdrawing rewards, you also have the option to deregister the staking key.", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 170, + "line": 160, "column": 16, - "index": 6260 + "index": 6206 }, "end": { - "line": 173, + "line": 163, "column": 3, - "index": 6443 + "index": 6389 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!Keeping the staking key will allow you to withdraw the rewards, but continue delegating to the same pool.", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 174, + "line": 164, "column": 16, - "index": 6461 + "index": 6407 }, "end": { - "line": 179, + "line": 169, "column": 3, - "index": 6685 + "index": 6631 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Deregistering the staking key will give you back your deposit and undelegate the key from any pool.", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 180, + "line": 170, "column": 16, - "index": 6703 + "index": 6649 }, "end": { - "line": 184, + "line": 174, "column": 3, - "index": 6910 + "index": 6856 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!!You do NOT need to deregister to delegate to a different stake pool. You can change your delegation preference at any time.", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 185, + "line": 175, "column": 12, - "index": 6924 + "index": 6870 }, "end": { - "line": 190, + "line": 180, "column": 3, - "index": 7155 + "index": 7101 } }, { @@ -79,14 +79,14 @@ "defaultMessage": "!!!You should NOT deregister if this staking key is used as a stake pool's reward account, as this will cause all pool operator rewards to be sent back to the reserve.", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 191, + "line": 181, "column": 12, - "index": 7169 + "index": 7115 }, "end": { - "line": 197, + "line": 187, "column": 3, - "index": 7452 + "index": 7398 } }, { @@ -94,14 +94,14 @@ "defaultMessage": "!!!Deregistering means this key will no longer receive rewards until you re-register the staking key (usually by delegating to a pool again)", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 198, + "line": 188, "column": 12, - "index": 7466 + "index": 7412 }, "end": { - "line": 203, + "line": 193, "column": 3, - "index": 7711 + "index": 7657 } }, { @@ -109,14 +109,14 @@ "defaultMessage": "!!!Keep registered", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 204, + "line": 194, "column": 14, - "index": 7727 + "index": 7673 }, "end": { - "line": 207, + "line": 197, "column": 3, - "index": 7835 + "index": 7781 } }, { @@ -124,14 +124,14 @@ "defaultMessage": "!!!Deregister", "file": "src/legacy/Dashboard/WithdrawStakingRewards/WithdrawStakingRewards.tsx", "start": { - "line": 208, + "line": 198, "column": 20, - "index": 7857 + "index": 7803 }, "end": { - "line": 211, + "line": 201, "column": 3, - "index": 7966 + "index": 7912 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/legacy/Staking/PoolTransition/usePoolTransition.json b/apps/wallet-mobile/translations/messages/src/legacy/Staking/PoolTransition/usePoolTransition.json index 1ec5530969..0c7ddff6bc 100644 --- a/apps/wallet-mobile/translations/messages/src/legacy/Staking/PoolTransition/usePoolTransition.json +++ b/apps/wallet-mobile/translations/messages/src/legacy/Staking/PoolTransition/usePoolTransition.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Upgrade your stake pool", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 127, + "line": 124, "column": 9, - "index": 4719 + "index": 4515 }, "end": { - "line": 130, + "line": 127, "column": 3, - "index": 4817 + "index": 4613 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!The current stake pool you're using will soon close. Migrate to the new EMURGO pool to sustain reward generation.", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 131, + "line": 128, "column": 11, - "index": 4830 + "index": 4626 }, "end": { - "line": 135, + "line": 132, "column": 3, - "index": 5026 + "index": 4822 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!The current stake pool you're using is decommissioned and NOT generating reward anymore. Update it to continue earning", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 136, + "line": 133, "column": 16, - "index": 5044 + "index": 4840 }, "end": { - "line": 140, + "line": 137, "column": 3, - "index": 5250 + "index": 5046 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Current pool", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 141, + "line": 138, "column": 15, - "index": 5267 + "index": 5063 }, "end": { - "line": 144, + "line": 141, "column": 3, - "index": 5360 + "index": 5156 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!!New pool", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 145, + "line": 142, "column": 11, - "index": 5373 + "index": 5169 }, "end": { - "line": 148, + "line": 145, "column": 3, - "index": 5458 + "index": 5254 } }, { @@ -79,14 +79,14 @@ "defaultMessage": "!!!Estimated ROA", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 149, + "line": 146, "column": 16, - "index": 5476 + "index": 5272 }, "end": { - "line": 152, + "line": 149, "column": 3, - "index": 5571 + "index": 5367 } }, { @@ -94,14 +94,14 @@ "defaultMessage": "!!!Fee", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 153, + "line": 150, "column": 7, - "index": 5580 + "index": 5376 }, "end": { - "line": 156, + "line": 153, "column": 3, - "index": 5656 + "index": 5452 } }, { @@ -109,14 +109,14 @@ "defaultMessage": "!!!This pool continues to generate staking rewards", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 157, + "line": 154, "column": 24, - "index": 5682 + "index": 5478 }, "end": { - "line": 160, + "line": 157, "column": 3, - "index": 5819 + "index": 5615 } }, { @@ -124,14 +124,14 @@ "defaultMessage": "!!!This pool is NOT generating staking rewards anymore", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 161, + "line": 158, "column": 17, - "index": 5838 + "index": 5634 }, "end": { - "line": 164, + "line": 161, "column": 3, - "index": 5972 + "index": 5768 } }, { @@ -139,14 +139,14 @@ "defaultMessage": "!!!This pool will stop generating rewards in", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 165, + "line": 162, "column": 23, - "index": 5997 + "index": 5793 }, "end": { - "line": 168, + "line": 165, "column": 3, - "index": 6127 + "index": 5923 } }, { @@ -154,14 +154,14 @@ "defaultMessage": "!!!Skip and stop receiving rewards", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 169, + "line": 166, "column": 17, - "index": 6146 + "index": 5942 }, "end": { - "line": 172, + "line": 169, "column": 3, - "index": 6260 + "index": 6056 } }, { @@ -169,14 +169,14 @@ "defaultMessage": "!!!Update now and keep earning", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 173, + "line": 170, "column": 21, - "index": 6283 + "index": 6079 }, "end": { - "line": 176, + "line": 173, "column": 3, - "index": 6397 + "index": 6193 } }, { @@ -184,14 +184,14 @@ "defaultMessage": "!!!Update pool", "file": "src/legacy/Staking/PoolTransition/usePoolTransition.tsx", "start": { - "line": 177, + "line": 174, "column": 10, - "index": 6409 + "index": 6205 }, "end": { - "line": 180, + "line": 177, "column": 3, - "index": 6496 + "index": 6292 } } ] \ No newline at end of file diff --git a/apps/wallet-mobile/translations/messages/src/legacy/Staking/StakingCenter/StakingCenter.json b/apps/wallet-mobile/translations/messages/src/legacy/Staking/StakingCenter/StakingCenter.json index 4f55b6775b..24ceee0b8c 100644 --- a/apps/wallet-mobile/translations/messages/src/legacy/Staking/StakingCenter/StakingCenter.json +++ b/apps/wallet-mobile/translations/messages/src/legacy/Staking/StakingCenter/StakingCenter.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Invalid Pool Data", "file": "src/legacy/Staking/StakingCenter/StakingCenter.tsx", "start": { - "line": 146, + "line": 139, "column": 9, - "index": 5740 + "index": 5214 }, "end": { - "line": 149, + "line": 142, "column": 3, - "index": 5848 + "index": 5322 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!The data from the stake pool(s) you selected is invalid. Please try again", "file": "src/legacy/Staking/StakingCenter/StakingCenter.tsx", "start": { - "line": 150, + "line": 143, "column": 11, - "index": 5861 + "index": 5335 }, "end": { - "line": 153, + "line": 146, "column": 3, - "index": 6027 + "index": 5501 } } ] \ No newline at end of file From 607884306fa104fe57b4d1da17f786997757a170 Mon Sep 17 00:00:00 2001 From: Javier Bueno Date: Thu, 24 Oct 2024 14:16:09 +0200 Subject: [PATCH 4/5] merge develop --- .../src/legacy/Staking/StakingCenter/StakingCenter.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx b/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx index 4e9f3fcfec..2986550471 100644 --- a/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx +++ b/apps/wallet-mobile/src/legacy/Staking/StakingCenter/StakingCenter.tsx @@ -6,7 +6,6 @@ import {StyleSheet, View} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' import {WebView, WebViewMessageEvent} from 'react-native-webview' import {useQueryClient} from 'react-query' -import {useQueryClient} from 'react-query' import {PleaseWaitModal} from '../../../components/PleaseWaitModal' import {Spacer} from '../../../components/Spacer/Spacer' @@ -19,7 +18,6 @@ import globalMessages from '../../../kernel/i18n/global-messages' import {logger} from '../../../kernel/logger/logger' import {useMetrics} from '../../../kernel/metrics/metricsManager' import {StakingCenterRouteNavigation, useWalletNavigation} from '../../../kernel/navigation' -import {StakingCenterRouteNavigation, useWalletNavigation} from '../../../kernel/navigation' import {NotEnoughMoneyToSendError} from '../../../yoroi-wallets/cardano/types' import {useStakingTx} from '../../Dashboard/StakePoolInfos' import {PoolDetailScreen} from '../PoolDetails' @@ -30,7 +28,6 @@ export const StakingCenter = () => { const {isDark} = useTheme() const {styles} = useStyles() const queryClient = useQueryClient() - const queryClient = useQueryClient() const {languageCode} = useLanguage() const {wallet, meta} = useSelectedWallet() From 6596120c03bb9918abc49727183ef713b53a0d54 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Thu, 24 Oct 2024 15:56:37 +0200 Subject: [PATCH 5/5] Suggestion to open PR (#3708) --- .../ReviewTx/common/hooks/useFormattedTx.tsx | 15 +-- .../features/ReviewTx/common/operations.tsx | 20 ++-- .../src/features/ReviewTx/common/types.ts | 96 ++++++++----------- 3 files changed, 57 insertions(+), 74 deletions(-) diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx index 419c218b1c..133c96b4e6 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/hooks/useFormattedTx.tsx @@ -1,4 +1,3 @@ -// import {CredKind} from '@emurgo/csl-mobile-bridge' import {CredKind} from '@emurgo/cross-csl-core' import {isNonNullable} from '@yoroi/common' import {infoExtractName} from '@yoroi/portfolio' @@ -14,8 +13,7 @@ import {asQuantity} from '../../../../yoroi-wallets/utils/utils' import {usePortfolioTokenInfos} from '../../../Portfolio/common/hooks/usePortfolioTokenInfos' import {useSelectedWallet} from '../../../WalletManager/common/hooks/useSelectedWallet' import { - Certificates, - FormattedCertificates, + FormattedCertificate, FormattedFee, FormattedInputs, FormattedOutputs, @@ -52,7 +50,7 @@ export const useFormattedTx = (data: TransactionBody): FormattedTx => { const formattedInputs = useFormattedInputs(wallet, inputs, portfolioTokenInfos) const formattedOutputs = useFormattedOutputs(wallet, outputs, portfolioTokenInfos) const formattedFee = formatFee(wallet, data) - const formattedCertificates = formatCertificates(data.certs as Certificates) + const formattedCertificates = formatCertificates(data.certs) return { inputs: formattedInputs, @@ -223,8 +221,13 @@ export const formatFee = (wallet: YoroiWallet, data: TransactionBody): Formatted } } -const formatCertificates = (certificates: Certificates) => { - return certificates.flatMap(Object.entries) as FormattedCertificates +const formatCertificates = (certificates: TransactionBody['certs']) => { + return ( + certificates?.map((cert) => { + const [type, certificate] = Object.entries(cert)[0] + return {type, certificate} as unknown as FormattedCertificate + }) ?? null + ) } const deriveAddress = async (address: string, chainId: number) => { diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx b/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx index e36e76288d..3c37ed4762 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx +++ b/apps/wallet-mobile/src/features/ReviewTx/common/operations.tsx @@ -12,7 +12,7 @@ import {asQuantity} from '../../../yoroi-wallets/utils/utils' import {useSelectedNetwork} from '../../WalletManager/common/hooks/useSelectedNetwork' import {useSelectedWallet} from '../../WalletManager/common/hooks/useSelectedWallet' import {useStrings} from './hooks/useStrings' -import {Certificate, CertificateTypes, FormattedCertificates} from './types' +import {CertificateType, FormattedTx} from './types' export const StakeRegistrationOperation = () => { const {styles} = useStyles() @@ -119,25 +119,25 @@ export const VoteDelegationOperation = ({drepID}: {drepID: string}) => { ) } -export const useOperations = (certificates: FormattedCertificates | null) => { +export const useOperations = (certificates: FormattedTx['certificates']) => { if (certificates === null) return [] - return certificates.reduce((acc, [certificateKind, CertificateData], index) => { - switch (certificateKind) { - case CertificateTypes.StakeRegistration: + return certificates.reduce((acc, certificate, index) => { + switch (certificate.type) { + case CertificateType.StakeRegistration: return [...acc, ] - case CertificateTypes.StakeDeregistration: + case CertificateType.StakeDeregistration: return [...acc, ] - case CertificateTypes.StakeDelegation: { - const poolKeyHash = (CertificateData as Certificate[CertificateTypes.StakeDelegation]).pool_keyhash ?? null + case CertificateType.StakeDelegation: { + const poolKeyHash = certificate.value.pool_keyhash ?? null if (poolKeyHash == null) return acc return [...acc, ] } - case CertificateTypes.VoteDelegation: { - const drep = (CertificateData as Certificate[CertificateTypes.VoteDelegation]).drep + case CertificateType.VoteDelegation: { + const drep = certificate.value.drep if (drep === 'AlwaysAbstain') return [...acc, ] if (drep === 'AlwaysNoConfidence') return [...acc, ] diff --git a/apps/wallet-mobile/src/features/ReviewTx/common/types.ts b/apps/wallet-mobile/src/features/ReviewTx/common/types.ts index 95d7a4ce05..fa11a20cf3 100644 --- a/apps/wallet-mobile/src/features/ReviewTx/common/types.ts +++ b/apps/wallet-mobile/src/features/ReviewTx/common/types.ts @@ -1,24 +1,8 @@ import { - CommitteeColdResignJSON, - CommitteeHotAuthJSON, - DRepDeregistrationJSON, - DRepRegistrationJSON, - DRepUpdateJSON, - GenesisKeyDelegationJSON, - MoveInstantaneousRewardsCertJSON, - PoolRegistrationJSON, - PoolRetirementJSON, - StakeAndVoteDelegationJSON, - StakeDelegationJSON, - StakeDeregistrationJSON, - StakeRegistrationAndDelegationJSON, - StakeRegistrationJSON, - StakeVoteRegistrationAndDelegationJSON, + CertificateJSON, TransactionBodyJSON, TransactionInputsJSON, TransactionOutputsJSON, - VoteDelegationJSON, - VoteRegistrationAndDelegationJSON, } from '@emurgo/cardano-serialization-lib-nodejs' import {CredKind} from '@emurgo/cross-csl-core' import {Balance, Portfolio} from '@yoroi/types' @@ -73,7 +57,7 @@ export type FormattedTx = { inputs: FormattedInputs outputs: FormattedOutputs fee: FormattedFee - certificates: FormattedCertificates | null + certificates: FormattedCertificate[] | null } export type FormattedMetadata = { @@ -81,45 +65,41 @@ export type FormattedMetadata = { metadata: {msg: Array} | null } -export type Certificates = Array -export type FormattedCertificates = Array<[CertificateTypes, Certificate[CertificateTypes]]> +type AssertEqual = T extends Expected + ? Expected extends T + ? true + : ['Type', Expected, 'is not equal to', T] + : ['Type', T, 'is not equal to', Expected] -export type Certificate = { - StakeRegistration: StakeRegistrationJSON - StakeDeregistration: StakeDeregistrationJSON - StakeDelegation: StakeDelegationJSON - PoolRegistration: PoolRegistrationJSON - PoolRetirement: PoolRetirementJSON - GenesisKeyDelegation: GenesisKeyDelegationJSON - MoveInstantaneousRewardsCert: MoveInstantaneousRewardsCertJSON - CommitteeHotAuth: CommitteeHotAuthJSON - CommitteeColdResign: CommitteeColdResignJSON - DRepDeregistration: DRepDeregistrationJSON - DRepRegistration: DRepRegistrationJSON - DRepUpdate: DRepUpdateJSON - StakeAndVoteDelegation: StakeAndVoteDelegationJSON - StakeRegistrationAndDelegation: StakeRegistrationAndDelegationJSON - StakeVoteRegistrationAndDelegation: StakeVoteRegistrationAndDelegationJSON - VoteDelegation: VoteDelegationJSON - VoteRegistrationAndDelegation: VoteRegistrationAndDelegationJSON -} +type UnionToIntersection = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never -export enum CertificateTypes { - StakeRegistration = 'StakeRegistration', - StakeDeregistration = 'StakeDeregistration', - StakeDelegation = 'StakeDelegation', - PoolRegistration = 'PoolRegistration', - PoolRetirement = 'PoolRetirement', - GenesisKeyDelegation = 'GenesisKeyDelegation', - MoveInstantaneousRewardsCert = 'MoveInstantaneousRewardsCert', - CommitteeHotAuth = 'CommitteeHotAuth', - CommitteeColdResign = 'CommitteeColdResign', - DRepDeregistration = 'DRepDeregistration', - DRepRegistration = 'DRepRegistration', - DRepUpdate = 'DRepUpdate', - StakeAndVoteDelegation = 'StakeAndVoteDelegation', - StakeRegistrationAndDelegation = 'StakeRegistrationAndDelegation', - StakeVoteRegistrationAndDelegation = 'StakeVoteRegistrationAndDelegation', - VoteDelegation = 'VoteDelegation', - VoteRegistrationAndDelegation = 'VoteRegistrationAndDelegation', -} +type Transformed = { + [K in keyof UnionToIntersection]: {type: K; value: UnionToIntersection[K]} +}[keyof UnionToIntersection] + +export type FormattedCertificate = Transformed + +export const CertificateType = { + StakeRegistration: 'StakeRegistration', + StakeDeregistration: 'StakeDeregistration', + StakeDelegation: 'StakeDelegation', + PoolRegistration: 'PoolRegistration', + PoolRetirement: 'PoolRetirement', + GenesisKeyDelegation: 'GenesisKeyDelegation', + MoveInstantaneousRewardsCert: 'MoveInstantaneousRewardsCert', + CommitteeHotAuth: 'CommitteeHotAuth', + CommitteeColdResign: 'CommitteeColdResign', + DRepDeregistration: 'DRepDeregistration', + DRepRegistration: 'DRepRegistration', + DRepUpdate: 'DRepUpdate', + StakeAndVoteDelegation: 'StakeAndVoteDelegation', + StakeRegistrationAndDelegation: 'StakeRegistrationAndDelegation', + StakeVoteRegistrationAndDelegation: 'StakeVoteRegistrationAndDelegation', + VoteDelegation: 'VoteDelegation', + VoteRegistrationAndDelegation: 'VoteRegistrationAndDelegation', +} as const + +export type CerificateType = (typeof CertificateType)[keyof typeof CertificateType] + +// Makes sure CertificateType lists all the certificates in CertificateJSON +export type AssertAllImplementedCertTypes = AssertEqual>