From 5a3ded09140fb390413b757fa076714bc2cdfb49 Mon Sep 17 00:00:00 2001 From: Daniel Dimitrov Date: Fri, 3 May 2024 17:11:26 +0200 Subject: [PATCH] feat: delete swap order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are persisting the order slice and if the users are making a lot of orders it can grow quite a lot. Since right now we are mainly interested in the state in order to show correct notifications, we can optimise and delete the order if the state is fulfilled, cancelled or expired. Those are final states - the next time we see them from the txHistory we can ignore them, if our redux state doesn’t have a created, open or presignaturePending state. If the previous state is undefined - this means that we are not interested in those final states and can ignore them. . --- src/store/__tests__/swapOrderSlice.test.ts | 79 +++++++++++++++++++++- src/store/swapOrderSlice.ts | 15 +++- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/src/store/__tests__/swapOrderSlice.test.ts b/src/store/__tests__/swapOrderSlice.test.ts index 46f4615a38..bb3a6861f4 100644 --- a/src/store/__tests__/swapOrderSlice.test.ts +++ b/src/store/__tests__/swapOrderSlice.test.ts @@ -1,6 +1,6 @@ import { listenerMiddlewareInstance } from '@/store' import { txHistorySlice } from '@/store/txHistorySlice' -import { swapOrderListener, swapOrderStatusListener, setSwapOrder } from '@/store/swapOrderSlice' +import { swapOrderListener, swapOrderStatusListener, setSwapOrder, deleteSwapOrder } from '@/store/swapOrderSlice' import { TransactionListItemType, type TransactionListItem, @@ -121,6 +121,37 @@ describe('swapOrderSlice', () => { }), ) }) + + it('should not dispatch setSwapOrder if the old status is undefined and new status is fulfilled, expired, or cancelled', () => { + const swapTransaction = { + type: TransactionListItemType.TRANSACTION, + transaction: { + id: '0x123', + txInfo: { + type: TransactionInfoType.SWAP_ORDER, + uid: 'order1', + status: 'fulfilled', // Test with 'expired' and 'cancelled' as well + }, + }, + } as unknown as TransactionListItem + + const action = txHistorySlice.actions.set({ + loading: false, + data: { + results: [swapTransaction], + }, + }) + + const effect = startListeningMock.mock.calls[0][0].effect + effect(action, { + dispatch: mockDispatch, + getOriginalState: () => ({ + swapOrders: {}, // Old status is undefined + }), + }) + + expect(mockDispatch).not.toHaveBeenCalled() + }) }) describe('swapOrderStatusListener', () => { @@ -167,7 +198,7 @@ describe('swapOrderSlice', () => { }) }) - it('should dispatch a notification if the swapOrder status is created and threshold is more than 1', () => { + it('should dispatch a notification if the swapOrder status is created and there is nothing about this swap in the state and threshold is more than 1', () => { const swapOrder = { orderUid: 'order1', status: 'created' as const, @@ -199,6 +230,43 @@ describe('swapOrderSlice', () => { }) }) + it('should dispatch a notification if the swapOrder status is open and we have old status and threshold is 1', () => { + const swapOrder = { + orderUid: 'order1', + status: 'open' as const, + txId: '0x123', + } + + const action = setSwapOrder(swapOrder) + + const effect = startListeningMock.mock.calls[0][0].effect + effect(action, { + dispatch: mockDispatch, + getState: () => ({ + safeInfo: { + data: { + threshold: 1, + }, + }, + }), + getOriginalState: () => ({ + swapOrders: { + order1: { + orderUid: 'order1', + status: 'created', // Old status is not undefined + }, + }, + }), + }) + + expect(showNotificationSpy).toHaveBeenCalledWith({ + title: 'Order created', + message: 'Waiting for the transaction to be executed', + groupKey: 'swap-order-status', + variant: 'info', + }) + }) + it('should dispatch a notification if the swapOrder status is presignaturePending', () => { const swapOrder = { orderUid: 'order1', @@ -325,6 +393,8 @@ describe('swapOrderSlice', () => { groupKey: 'swap-order-status', variant: 'info', }) + + expect(mockDispatch).toHaveBeenCalledWith(deleteSwapOrder('order1')) }) it('should not dispatch a notification if the swapOrder status is expired and old status is undefined', () => { @@ -352,6 +422,7 @@ describe('swapOrderSlice', () => { }) expect(showNotificationSpy).not.toHaveBeenCalled() + expect(mockDispatch).not.toHaveBeenCalledWith(deleteSwapOrder('order1')) }) it('should dispatch a notification if the swapOrder status is expired and old status is not undefined', () => { @@ -389,6 +460,8 @@ describe('swapOrderSlice', () => { groupKey: 'swap-order-status', variant: 'warning', }) + + expect(mockDispatch).toHaveBeenCalledWith(deleteSwapOrder('order1')) }) it('should not dispatch a notification if the swapOrder status is cancelled and old status is undefined', () => { @@ -416,6 +489,7 @@ describe('swapOrderSlice', () => { }) expect(showNotificationSpy).not.toHaveBeenCalled() + expect(mockDispatch).not.toHaveBeenCalledWith(deleteSwapOrder('order1')) }) it('should dispatch a notification if the swapOrder status is cancelled and old status is not undefined', () => { @@ -453,6 +527,7 @@ describe('swapOrderSlice', () => { groupKey: 'swap-order-status', variant: 'warning', }) + expect(mockDispatch).toHaveBeenCalledWith(deleteSwapOrder('order1')) }) }) }) diff --git a/src/store/swapOrderSlice.ts b/src/store/swapOrderSlice.ts index 12edc54019..3f8c0bed79 100644 --- a/src/store/swapOrderSlice.ts +++ b/src/store/swapOrderSlice.ts @@ -33,10 +33,15 @@ const slice = createSlice({ }, } }, + deleteSwapOrder: (state, { payload }: { payload: string }): SwapOrderState => { + const newState = { ...state } + delete newState[payload] + return newState + }, }, }) -export const { setSwapOrder } = slice.actions +export const { setSwapOrder, deleteSwapOrder } = slice.actions const selector = (state: RootState) => state[slice.name] export const swapOrderSlice = slice export const selectAllSwapOrderStatuses = selector @@ -72,7 +77,7 @@ export const swapOrderStatusListener = (listenerMiddleware: typeof listenerMiddl const oldStatus = selectSwapOrderStatus(listenerApi.getOriginalState(), swapOrder.orderUid) const newStatus = swapOrder.status - if (oldStatus === newStatus) { + if (oldStatus === newStatus || newStatus === undefined) { return } @@ -125,6 +130,7 @@ export const swapOrderStatusListener = (listenerMiddleware: typeof listenerMiddl variant: 'info', }), ) + dispatch(slice.actions.deleteSwapOrder(swapOrder.orderUid)) break case 'expired': if (oldStatus === undefined) { @@ -138,6 +144,7 @@ export const swapOrderStatusListener = (listenerMiddleware: typeof listenerMiddl variant: 'warning', }), ) + dispatch(slice.actions.deleteSwapOrder(swapOrder.orderUid)) break case 'cancelled': if (oldStatus === undefined) { @@ -151,6 +158,7 @@ export const swapOrderStatusListener = (listenerMiddleware: typeof listenerMiddl variant: 'warning', }), ) + dispatch(slice.actions.deleteSwapOrder(swapOrder.orderUid)) break } }, @@ -178,7 +186,8 @@ export const swapOrderListener = (listenerMiddleware: typeof listenerMiddlewareI const swapOrder = result.transaction.txInfo const oldStatus = selectSwapOrderStatus(listenerApi.getOriginalState(), swapOrder.uid) - if (oldStatus === swapOrder.status) { + const finalStatuses: AllStatuses[] = ['fulfilled', 'expired', 'cancelled'] + if (oldStatus === swapOrder.status || (oldStatus === undefined && finalStatuses.includes(swapOrder.status))) { continue }