Skip to content

Commit

Permalink
fix(trading): cleaning of modal account key
Browse files Browse the repository at this point in the history
  • Loading branch information
adderpositive authored and tomasklim committed Mar 3, 2025
1 parent 41d8bdd commit 2a761d4
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { invityAPI } from '@suite-common/trading';
import { UI } from '@trezor/connect';

import { MODAL, ROUTER } from 'src/actions/suite/constants';
import { TRADING_COMMON } from 'src/actions/wallet/constants';
Expand Down Expand Up @@ -42,6 +41,18 @@ const TRADING_EXCHANGE_ROUTE = {
url: '/accounts/coinmarket/exchange#/btc/0/normal',
};

const DEFAULT_ROUTE = {
loaded: false,
url: '/',
pathname: '/',
app: 'unknown',
route: undefined,
params: undefined,
settingsBackRoute: {
name: 'suite-index',
},
} as RouterState;

type TradingState = ReturnType<typeof tradingReducer>;
type SelectedAccountState = ReturnType<typeof selectedAccountReducer>;
type SuiteState = ReturnType<typeof suiteReducer>;
Expand All @@ -54,7 +65,7 @@ interface Args {
modal?: ModalState;
}

const getInitialState = ({ trading, selectedAccount }: Args = {}) => ({
const getInitialState = ({ trading, selectedAccount, router }: Args = {}) => ({
wallet: {
trading:
trading ||
Expand Down Expand Up @@ -85,20 +96,7 @@ const getInitialState = ({ trading, selectedAccount }: Args = {}) => ({
} as any,
{ type: 'foo' } as any,
),
router: routerReducer(
{
loaded: false,
url: '/',
pathname: '/',
app: 'unknown',
route: undefined,
params: undefined,
settingsBackRoute: {
name: 'suite-index',
},
} as RouterState,
{} as Action,
),
router: router ?? routerReducer(DEFAULT_ROUTE, {} as Action),
modal: modalReducer({ context: MODAL.CONTEXT_NONE }, {} as Action),
});

Expand Down Expand Up @@ -229,71 +227,30 @@ describe('tradingMiddleware', () => {
expect(setInvityServersEnvironmentMock).toHaveBeenCalledTimes(0);
});

it('Test of cleaning modalAccountKey property after receive modal is closed', () => {
it('should clean modalAccountKey after leaving trading', () => {
const store = initStore(
getInitialState({
trading: {
...initialState,
modalAccountKey: accounts[0].key,
lastLoadedTimestamp: Date.now(),
},
router: routerReducer(TRADING_EXCHANGE_ROUTE as RouterState, {} as Action),
}),
);

// go to trading
// go away from trading
store.dispatch({
type: ROUTER.LOCATION_CHANGE,
payload: TRADING_EXCHANGE_ROUTE,
});

// open modal
store.dispatch({
type: UI.REQUEST_BUTTON,
payload: {
context: MODAL.CONTEXT_DEVICE,
code: 'ButtonRequest_Address',
},
});

// close modal
store.dispatch({
type: UI.CLOSE_UI_WINDOW,
});

expect(store.getState().wallet.trading.modalAccountKey).toEqual(undefined);
});

it('Test of cleaning modalAccountKey property after send modal is closed', () => {
const store = initStore(
getInitialState({
trading: {
...initialState,
modalAccountKey: accounts[0].key,
lastLoadedTimestamp: Date.now(),
...DEFAULT_ROUTE,
route: {
...DEFAULT_ROUTE.route,
name: 'suite-start',
},
}),
);

// go to trading
store.dispatch({
type: ROUTER.LOCATION_CHANGE,
payload: TRADING_EXCHANGE_ROUTE,
});

// open modal
store.dispatch({
type: UI.REQUEST_BUTTON,
payload: {
context: MODAL.CONTEXT_DEVICE,
code: 'ButtonRequest_SignTx',
},
});

// close modal
store.dispatch({
type: MODAL.CLOSE,
});

expect(store.getState().wallet.trading.modalAccountKey).toEqual(undefined);
});

Expand All @@ -303,6 +260,9 @@ describe('tradingMiddleware', () => {
trading: {
...initialState,
},
router: {
...getInitialState().router,
},
}),
);

Expand Down
38 changes: 8 additions & 30 deletions packages/suite/src/middlewares/wallet/tradingMiddleware.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { MiddlewareAPI } from 'redux';

import { INVITY_API_RELOAD_DATA_AFTER_MS, invityAPI } from '@suite-common/trading';
import { UI } from '@trezor/connect';

import { MODAL, ROUTER } from 'src/actions/suite/constants';
import { ROUTER } from 'src/actions/suite/constants';
import { TRADING_COMMON, TRADING_EXCHANGE, TRADING_SELL } from 'src/actions/wallet/constants';
import * as tradingCommonActions from 'src/actions/wallet/trading/tradingCommonActions';
import * as tradingBuyActions from 'src/actions/wallet/tradingBuyActions';
Expand Down Expand Up @@ -41,10 +40,9 @@ export const tradingMiddleware =
(next: Dispatch) =>
(action: Action): Action => {
const state = api.getState();
const { isLoading, lastLoadedTimestamp } = state.wallet.trading;
const { isLoading, lastLoadedTimestamp, modalAccountKey } = state.wallet.trading;
const { exchangeInfo } = state.wallet.trading.exchange;
const { sellInfo } = state.wallet.trading.sell;
const { router, modal } = state;
const isRouteChange = action.type === ROUTER.LOCATION_CHANGE;

if (action.type === TRADING_COMMON.LOAD_DATA) {
Expand Down Expand Up @@ -115,43 +113,23 @@ export const tradingMiddleware =
}
}

const isTradingRoute = !!router.route?.name.includes('wallet-trading');
const isDeviceContext = modal.context === MODAL.CONTEXT_DEVICE;
const isUserContext = modal.context === MODAL.CONTEXT_USER;

const isCloseUiWindowEvent = action.type === UI.CLOSE_UI_WINDOW;
const isReceiveModal =
isCloseUiWindowEvent && isDeviceContext && modal.windowType === 'ButtonRequest_Address';

/*
isCloseEvent
- happens only one time when the whole flow of sending the transaction is closed
- isCloseUiWindowEvent can not be used, it is called multiple times during flow because of
changing context from CONTEXT_DEVICE (sign transaction) to CONTEXT_USER (summary)
*/
const isCloseEvent = action.type === MODAL.CLOSE;
const isOtherFlow = isDeviceContext && modal.windowType === `ButtonRequest_Other`; // passphrase request, etc.
const isSigningFlow = isDeviceContext && modal.windowType === 'ButtonRequest_SignTx';
const isSummaryFlow = isUserContext && modal.payload.type === 'review-transaction';
const isSendModal = isCloseEvent && (isOtherFlow || isSigningFlow || isSummaryFlow);

// clear modal account on close button requests
// it is necessary to clear the state because it could affect the next modal state
if (isTradingRoute && (isReceiveModal || isSendModal)) {
api.dispatch(tradingCommonActions.setTradingModalAccountKey(undefined));
}

next(action);

// get the new state after the action has been processed
const newState = api.getState();

if (isRouteChange) {
const routeName = newState.router.route?.name;
const isTradingRoute = !!routeName?.includes('wallet-trading');
const isBuy = routeName === 'wallet-trading-buy';
const isSell = routeName === 'wallet-trading-sell';
const isExchange = routeName === 'wallet-trading-exchange';

// it is necessary to clear the state because it could affect the other modal state
if (!isTradingRoute && modalAccountKey) {
api.dispatch(tradingCommonActions.setTradingModalAccountKey(undefined));
}

if (isBuy) {
api.dispatch(tradingCommonActions.setActiveSection('buy'));
api.dispatch(tradingBuyActions.saveTransactionDetailId(undefined));
Expand Down

0 comments on commit 2a761d4

Please sign in to comment.