Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 4.1.2 #786

Merged
merged 11 commits into from
Apr 8, 2024
2 changes: 1 addition & 1 deletion packages/mobile/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 433
versionName "4.1.0"
versionName "4.1.2"
missingDimensionStrategy 'react-native-camera', 'general'
missingDimensionStrategy 'store', 'play'
}
Expand Down
15 changes: 8 additions & 7 deletions packages/mobile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import crashlytics from '@react-native-firebase/crashlytics';
import messaging from '@react-native-firebase/messaging';
import { withIAPContext } from 'react-native-iap';
import { startApp } from './src/index';
import { tk } from './src/wallet';

LogBox.ignoreLogs([
'Non-serializable values were found in the navigation state',
Expand All @@ -47,15 +46,17 @@ async function handleDappMessage(remoteMessage) {
) {
return null;
}

await useNotificationsStore.persist.rehydrate();
if (remoteMessage.data?.type === 'better_stake_option_found') {
tk.wallet.staking.toggleRestakeBanner(
true,
remoteMessage.data.stakingAddressToMigrateFrom,
);
useNotificationsStore
.getState()
.actions.toggleRestakeBanner(
remoteMessage.data.account,
true,
remoteMessage.data.stakingAddressToMigrateFrom,
);
}

await useNotificationsStore.persist.rehydrate();
useNotificationsStore.getState().actions.addNotification(
{
...remoteMessage.data,
Expand Down
4 changes: 2 additions & 2 deletions packages/mobile/ios/ton_keeper.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1294,7 +1294,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 4.1.0;
MARKETING_VERSION = 4.1.2;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -1328,7 +1328,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 4.1.0;
MARKETING_VERSION = 4.1.2;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down
49 changes: 31 additions & 18 deletions packages/mobile/src/components/RestakeBanner/RestakeBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { IconsComposition } from './IconsComposition';
import { useFiatValue } from '$hooks/useFiatValue';
import { CryptoCurrencies } from '$shared/constants';
import { stakingFormatter } from '$utils/formatter';
import { useNotificationsStore } from '$store';

export interface ExtendedPoolInfo extends PoolInfo {
isWithdrawal: boolean;
Expand All @@ -35,6 +36,7 @@ export interface ExtendedPoolInfo extends PoolInfo {
export interface RestakeBannerProps {
poolsList: ExtendedPoolInfo[];
migrateFrom: string;
bypassUnstakeStep?: boolean;
}

export enum RestakeSteps {
Expand All @@ -52,11 +54,14 @@ export const RestakeBanner = memo<RestakeBannerProps>((props) => {
) as ExtendedPoolInfo;
}, [props.poolsList]);
const { handleTopUpPress } = usePoolInfo(tonstakersPool);
const toggleRestakeBanner = useNotificationsStore(
(state) => state.actions.toggleRestakeBanner,
);

const handleCloseRestakeBanner = useCallback(() => {
LayoutAnimation.easeInEaseOut();
tk.wallet.staking.toggleRestakeBanner(false);
}, []);
toggleRestakeBanner(tk.wallet.address.ton.raw, false);
}, [toggleRestakeBanner]);

const poolToWithdrawal = useMemo(
() =>
Expand All @@ -68,8 +73,6 @@ export const RestakeBanner = memo<RestakeBannerProps>((props) => {
[poolToWithdrawal],
);

const bypassStakeStep = useStakingState((s) => s.bypassStakeStep, []);

const readyWithdraw = useFiatValue(
CryptoCurrencies.Ton,
stakingFormatter.fromNano(toWithdrawalStakingInfo?.ready_withdraw ?? '0'),
Expand All @@ -79,13 +82,17 @@ export const RestakeBanner = memo<RestakeBannerProps>((props) => {

const handleWithdrawal = useCallback(
(pool: ExtendedPoolInfo, withdrawAll?: boolean) => () => {
if (pool.implementation === PoolImplementationType.Tf) {
nav.push(AppStackRouteNames.StakingSend, {
poolAddress: pool.address,
transactionType: StakingTransactionType.WITHDRAWAL_CONFIRM,
});
return;
}
nav.push(AppStackRouteNames.StakingSend, {
amount: withdrawAll && pool.balance,
poolAddress: pool.address,
transactionType:
pool.implementation === PoolImplementationType.Tf
? StakingTransactionType.WITHDRAWAL_CONFIRM
: StakingTransactionType.WITHDRAWAL,
transactionType: StakingTransactionType.WITHDRAWAL,
});
},
[nav],
Expand All @@ -107,7 +114,11 @@ export const RestakeBanner = memo<RestakeBannerProps>((props) => {
return RestakeSteps.DONE;
}
// Go to last step if pool to withdrawal is empty now (or if balance so small, or step is bypassed)
if (bypassStakeStep || Number(poolToWithdrawal?.balance) < 0.1) {
if (
props.bypassUnstakeStep ||
!poolToWithdrawal?.balance ||
Number(poolToWithdrawal?.balance) < 0.1
) {
return RestakeSteps.STAKE_INTO_TONSTAKERS;
}
// If user has pending withdrawal, render step with waiting
Expand All @@ -116,7 +127,7 @@ export const RestakeBanner = memo<RestakeBannerProps>((props) => {
}
return RestakeSteps.UNSTAKE;
}, [
bypassStakeStep,
props.bypassUnstakeStep,
isWaitingForWithdrawal,
poolToWithdrawal?.balance,
readyWithdraw.amount,
Expand All @@ -130,8 +141,8 @@ export const RestakeBanner = memo<RestakeBannerProps>((props) => {
}, [currentStepId, handleCloseRestakeBanner]);

const { formattedDuration, isCooldown } = useStakingCycle(
poolToWithdrawal?.cycle_start,
poolToWithdrawal?.cycle_end,
poolToWithdrawal?.cycle_start ?? Date.now(),
poolToWithdrawal?.cycle_end ?? Date.now(),
isWaitingForWithdrawal,
);

Expand Down Expand Up @@ -195,12 +206,14 @@ export const RestakeBanner = memo<RestakeBannerProps>((props) => {
}),
})}
/>,
<Button
color="tertiary"
size="small"
onPress={handleWithdrawal(poolToWithdrawal)}
title={t('restake_banner.unstake_action_manual')}
/>,
poolToWithdrawal.implementation !== PoolImplementationType.Tf && (
<Button
color="tertiary"
size="small"
onPress={handleWithdrawal(poolToWithdrawal)}
title={t('restake_banner.unstake_action_manual')}
/>
),
]
}
stepId={RestakeSteps.UNSTAKE}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const DeleteAccountDone: React.FC = () => {
}, []);

const handleAnimationEnd = useCallback(() => {
dispatch(walletActions.cleanWallet({ cleanAll: true }));
dispatch(walletActions.cleanWallet({ cleanAll: false }));
}, [dispatch]);

return (
Expand Down
6 changes: 5 additions & 1 deletion packages/mobile/src/core/Notifications/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
disableNotifications,
useConnectedAppsList,
useDAppsNotifications,
useNotificationsStore,
} from '$store';
import { format, getDomainFromURL } from '$utils';
import { Swipeable, TouchableOpacity } from 'react-native-gesture-handler';
Expand Down Expand Up @@ -54,6 +55,9 @@ export const Notification: React.FC<NotificationProps> = (props) => {
const { showActionSheetWithOptions } = useActionSheet();
const { deleteNotificationByReceivedAt } = useDAppsNotifications();
const listItemRef = useRef(null);
const toggleRestakeBanner = useNotificationsStore(
(state) => state.actions.toggleRestakeBanner,
);

const handleDelete = useCallback(() => {
deleteNotificationByReceivedAt(props.notification.received_at);
Expand Down Expand Up @@ -141,7 +145,7 @@ export const Notification: React.FC<NotificationProps> = (props) => {

const handleOpenInWebView = useCallback(() => {
if (props.notification.type === NotificationType.BETTER_STAKE_OPTION_FOUND) {
tk.wallet.staking.toggleRestakeBanner(true);
toggleRestakeBanner(tk.wallet.address.ton.raw, true);
}

if (!props.notification.link && !props.notification.deeplink) {
Expand Down
30 changes: 17 additions & 13 deletions packages/mobile/src/core/Settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,20 +211,24 @@ export const Settings: FC = () => {
}, []);

const handleDeleteAccount = useCallback(() => {
Alert.alert(t('settings_delete_alert_title'), t('settings_delete_alert_caption'), [
{
text: t('cancel'),
style: 'cancel',
},
{
text: t('settings_delete_alert_button'),
style: 'destructive',
onPress: () => {
trackEvent('delete_wallet');
openDeleteAccountDone();
Alert.alert(
t('settings_delete_alert_title', { space: Platform.OS === 'ios' ? '\n' : ' ' }),
t('settings_delete_alert_caption'),
[
{
text: t('cancel'),
style: 'cancel',
},
},
]);
{
text: t('settings_delete_alert_button'),
style: 'destructive',
onPress: () => {
trackEvent('delete_wallet');
openDeleteAccountDone();
},
},
],
);
}, []);

const handleCustomizePress = useCallback(
Expand Down
32 changes: 19 additions & 13 deletions packages/mobile/src/core/Staking/Staking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useStakingRefreshControl } from '$hooks/useStakingRefreshControl';
import { useNavigation } from '@tonkeeper/router';
import { MainStackRouteNames, openDAppBrowser } from '$navigation';
import { StakingListCell } from '$shared/components';
import { FlashCountKeys, useFlashCount } from '$store';
import { FlashCountKeys, useFlashCount, useNotificationsStore } from '$store';
import { Button, Icon, ScrollHandler, Spacer, Text } from '$uikit';
import { List } from '$uikit/List/old/List';
import { getImplementationIcon, getPoolIcon } from '$utils/staking';
Expand All @@ -24,6 +24,8 @@ import { useBalancesState, useJettons, useStakingState } from '@tonkeeper/shared
import { StakingManager, StakingProvider } from '$wallet/managers/StakingManager';
import { config } from '$config';
import { RestakeBanner } from '../../components/RestakeBanner/RestakeBanner';
import { shallow } from 'zustand/shallow';
import { tk } from '$wallet';

interface Props {}

Expand All @@ -36,9 +38,11 @@ export const Staking: FC<Props> = () => {
const pools = useStakingState((s) => s.pools);
const stakingInfo = useStakingState((s) => s.stakingInfo);
const highestApyPool = useStakingState((s) => s.highestApyPool);
const showRestakeBanner = useStakingState((s) => s.showRestakeBanner);
const stakingAddressToMigrateFrom = useStakingState(
(s) => s.stakingAddressToMigrateFrom,

const rawAddress = tk.wallet.address.ton.raw ?? '';
const notificationsStore = useNotificationsStore(
(state) => state.wallets[rawAddress],
shallow,
);

const [flashShownCount] = useFlashCount(FlashCountKeys.Staking);
Expand Down Expand Up @@ -221,15 +225,17 @@ export const Staking: FC<Props> = () => {
showsVerticalScrollIndicator={false}
>
<S.Content bottomInset={bottomInset}>
{showRestakeBanner && stakingAddressToMigrateFrom && (
<>
<RestakeBanner
migrateFrom={stakingAddressToMigrateFrom}
poolsList={poolsList}
/>
<Spacer y={16} />
</>
)}
{notificationsStore?.showRestakeBanner &&
notificationsStore?.stakingAddressToMigrateFrom && (
<>
<RestakeBanner
bypassUnstakeStep={notificationsStore?.bypassUnstakeStep}
migrateFrom={notificationsStore?.stakingAddressToMigrateFrom}
poolsList={poolsList}
/>
<Spacer y={16} />
</>
)}
{!hasActivePools ? (
<S.LargeTitleContainer>
<Text variant="h2">{t('staking.title_large')}</Text>
Expand Down
38 changes: 29 additions & 9 deletions packages/mobile/src/core/StakingSend/StakingSend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { AppStackRouteNames } from '$navigation';
import { AppStackParamList } from '$navigation/AppStack';
import { StepView, StepViewItem, StepViewRef } from '$shared/components';
import { CryptoCurrencies, Decimals } from '$shared/constants';
import { Toast } from '$store';
import { Toast, useNotificationsStore } from '$store';
import { getStakingPoolByAddress } from '@tonkeeper/shared/utils/staking';
import { walletWalletSelector } from '$store/wallet';
import { NavBar } from '$uikit';
Expand Down Expand Up @@ -38,6 +38,7 @@ import { SignRawMessage } from '$core/ModalContainer/NFTOperations/TXRequest.typ
import { useStakingState, useWallet } from '@tonkeeper/shared/hooks';
import { tk } from '$wallet';
import { Address } from '@tonkeeper/shared/Address';
import { shallow } from 'zustand/shallow';

interface Props {
route: RouteProp<AppStackParamList, AppStackRouteNames.StakingSend>;
Expand Down Expand Up @@ -176,6 +177,15 @@ export const StakingSend: FC<Props> = (props) => {

const messages = useRef<SignRawMessage[]>([]);

const rawAddress = wallet.address.ton.raw ?? '';
const stakingAddressToMigrateFrom = useNotificationsStore(
(state) => state.wallets[rawAddress]?.stakingAddressToMigrateFrom,
shallow,
);
const bypassUnstakeStep = useNotificationsStore(
(state) => state.actions.bypassUnstakeStep,
);

const { isLiquidJetton, price } = useCurrencyToSend(currency, tokenType);

const parsedAmount = useMemo(() => {
Expand Down Expand Up @@ -334,22 +344,32 @@ export const StakingSend: FC<Props> = (props) => {
const privateKey = await vault.getTonPrivateKey();

await actionRef.current.send(privateKey);

const endTimestamp = pool.cycle_end * 1000;
const isCooldown = Date.now() > endTimestamp;

if (
isWithdrawalConfrim &&
tk.wallet.staking.state.data.stakingAddressToMigrateFrom &&
Address.compare(
tk.wallet.staking.state.data.stakingAddressToMigrateFrom,
pool.address,
)
(isWithdrawalConfrim || isCooldown) &&
stakingAddressToMigrateFrom &&
Address.compare(stakingAddressToMigrateFrom, pool.address)
) {
tk.wallet.staking.setBypassStakeStep();
bypassUnstakeStep(rawAddress);
}
} catch (e) {
throw e;
} finally {
setSending(false);
}
}, [isDeposit, isWithdrawalConfrim, pool, totalFee, unlockVault]);
}, [
bypassUnstakeStep,
isDeposit,
isWithdrawalConfrim,
pool,
rawAddress,
stakingAddressToMigrateFrom,
totalFee,
unlockVault,
]);

useEffect(() => {
if (isWithdrawalConfrim || initialAmount) {
Expand Down
Loading
Loading