From 796dacdabc93e91e6fa3b12777dd2c705584851e Mon Sep 17 00:00:00 2001 From: Daniel <80175477+dan437@users.noreply.github.com> Date: Thu, 4 Nov 2021 16:45:04 +0100 Subject: [PATCH] State changes + getTransactions fn (#16) * Process a batchStatus response correctly, since it was reorganized * Update a list of smart transactions properly * Use "smartTransactionsState", add a new "getTransactions" fn * Update UTs to support the "smartTransactionsState" namespace --- src/SmartTransactionsController.test.ts | 81 ++++++++++++++-------- src/SmartTransactionsController.ts | 92 ++++++++++++++++++------- 2 files changed, 120 insertions(+), 53 deletions(-) diff --git a/src/SmartTransactionsController.test.ts b/src/SmartTransactionsController.test.ts index 6a38e756..fd0ecd39 100644 --- a/src/SmartTransactionsController.test.ts +++ b/src/SmartTransactionsController.test.ts @@ -16,6 +16,8 @@ jest.mock('ethers', () => ({ getTransactionReceipt = jest.fn(() => ({ blockNumber: '123' })); + getTransaction = jest.fn(); + getBlock = jest.fn(); }, }, @@ -224,10 +226,12 @@ describe('SmartTransactionsController', () => { it('initializes with default state', () => { expect(smartTransactionsController.state).toStrictEqual({ - smartTransactions: { - [CHAIN_IDS.ETHEREUM]: [], + smartTransactionsState: { + smartTransactions: { + [CHAIN_IDS.ETHEREUM]: [], + }, + userOptIn: undefined, }, - userOptIn: undefined, }); }); @@ -286,11 +290,17 @@ describe('SmartTransactionsController', () => { describe('setOptInState', () => { it('sets optIn state', () => { smartTransactionsController.setOptInState(true); - expect(smartTransactionsController.state.userOptIn).toBe(true); + expect( + smartTransactionsController.state.smartTransactionsState.userOptIn, + ).toBe(true); smartTransactionsController.setOptInState(false); - expect(smartTransactionsController.state.userOptIn).toBe(false); + expect( + smartTransactionsController.state.smartTransactionsState.userOptIn, + ).toBe(false); smartTransactionsController.setOptInState(undefined); - expect(smartTransactionsController.state.userOptIn).toBeUndefined(); + expect( + smartTransactionsController.state.smartTransactionsState.userOptIn, + ).toBeUndefined(); }); }); @@ -326,9 +336,8 @@ describe('SmartTransactionsController', () => { }); expect( - smartTransactionsController.state.smartTransactions[ - CHAIN_IDS.ETHEREUM - ][0].uuid, + smartTransactionsController.state.smartTransactionsState + .smartTransactions[CHAIN_IDS.ETHEREUM][0].uuid, ).toStrictEqual('dP23W7c2kt4FK9TmXOkz1UM2F20'); }); }); @@ -342,10 +351,12 @@ describe('SmartTransactionsController', () => { .reply(200, pendingBatchStatusApiResponse); await smartTransactionsController.fetchSmartTransactionsStatus(uuids); expect(smartTransactionsController.state).toStrictEqual({ - smartTransactions: { - [CHAIN_IDS.ETHEREUM]: createStateAfterPending(), + smartTransactionsState: { + smartTransactions: { + [CHAIN_IDS.ETHEREUM]: createStateAfterPending(), + }, + userOptIn: undefined, }, - userOptIn: undefined, }); }); @@ -353,8 +364,11 @@ describe('SmartTransactionsController', () => { const uuids = ['uuid2']; const successBatchStatusApiResponse = createSuccessBatchStatusApiResponse(); smartTransactionsController.update({ - smartTransactions: { - [CHAIN_IDS.ETHEREUM]: createStateAfterPending() as SmartTransaction[], + smartTransactionsState: { + ...smartTransactionsController.state.smartTransactionsState, + smartTransactions: { + [CHAIN_IDS.ETHEREUM]: createStateAfterPending() as SmartTransaction[], + }, }, }); @@ -362,14 +376,18 @@ describe('SmartTransactionsController', () => { .get(`/networks/${ethereumChainIdDec}/batchStatus?uuids=uuid2`) .reply(200, successBatchStatusApiResponse); await smartTransactionsController.fetchSmartTransactionsStatus(uuids); - expect(smartTransactionsController.state).toStrictEqual({ - smartTransactions: { - [CHAIN_IDS.ETHEREUM]: [ - ...createStateAfterPending(), - ...createStateAfterSuccess(), - ], + expect( + smartTransactionsController.state.smartTransactionsState, + ).toStrictEqual({ + smartTransactionsState: { + smartTransactions: { + [CHAIN_IDS.ETHEREUM]: [ + ...createStateAfterPending(), + ...createStateAfterSuccess(), + ], + }, + userOptIn: undefined, }, - userOptIn: undefined, }); }); }); @@ -388,9 +406,13 @@ describe('SmartTransactionsController', () => { describe('updateSmartTransaction', () => { it('updates smart transaction based on uuid', () => { const pendingStx = createStateAfterPending()[0]; + const { smartTransactionsState } = smartTransactionsController.state; smartTransactionsController.update({ - smartTransactions: { - [CHAIN_IDS.ETHEREUM]: [pendingStx] as SmartTransaction[], + smartTransactionsState: { + ...smartTransactionsState, + smartTransactions: { + [CHAIN_IDS.ETHEREUM]: [pendingStx] as SmartTransaction[], + }, }, }); const updateTransaction = { @@ -402,21 +424,24 @@ describe('SmartTransactionsController', () => { ); expect( - smartTransactionsController.state.smartTransactions[ - CHAIN_IDS.ETHEREUM - ][0].status, + smartTransactionsController.state.smartTransactionsState + .smartTransactions[CHAIN_IDS.ETHEREUM][0].status, ).toStrictEqual('test'); }); it('confirms a smart transaction that has status success', async () => { + const { smartTransactionsState } = smartTransactionsController.state; const confirmSpy = jest.spyOn( smartTransactionsController, 'confirmSmartTransaction', ); const pendingStx = createStateAfterPending()[0]; smartTransactionsController.update({ - smartTransactions: { - [CHAIN_IDS.ETHEREUM]: [pendingStx] as SmartTransaction[], + smartTransactionsState: { + ...smartTransactionsState, + smartTransactions: { + [CHAIN_IDS.ETHEREUM]: [pendingStx] as SmartTransaction[], + }, }, }); const updateTransaction = { diff --git a/src/SmartTransactionsController.ts b/src/SmartTransactionsController.ts index 3a7fb423..3d3d39af 100644 --- a/src/SmartTransactionsController.ts +++ b/src/SmartTransactionsController.ts @@ -45,8 +45,10 @@ export interface SmartTransactionsControllerConfig extends BaseConfig { } export interface SmartTransactionsControllerState extends BaseState { - smartTransactions: Record; - userOptIn: boolean | undefined; + smartTransactionsState: { + smartTransactions: Record; + userOptIn: boolean | undefined; + }; } export default class SmartTransactionsController extends BaseController< @@ -106,8 +108,10 @@ export default class SmartTransactionsController extends BaseController< }; this.defaultState = { - smartTransactions: {}, - userOptIn: undefined, + smartTransactionsState: { + smartTransactions: {}, + userOptIn: undefined, + }, }; this.nonceTracker = nonceTracker; @@ -131,11 +135,16 @@ export default class SmartTransactionsController extends BaseController< initializeSmartTransactionsForChainId() { if (this.config.supportedChainIds.includes(this.config.chainId)) { + const { smartTransactionsState } = this.state; this.update({ - smartTransactions: { - ...this.state.smartTransactions, - [this.config.chainId]: - this.state.smartTransactions[this.config.chainId] ?? [], + smartTransactionsState: { + ...smartTransactionsState, + smartTransactions: { + ...smartTransactionsState.smartTransactions, + [this.config.chainId]: + smartTransactionsState.smartTransactions[this.config.chainId] ?? + [], + }, }, }); } @@ -159,12 +168,18 @@ export default class SmartTransactionsController extends BaseController< } setOptInState(state: boolean | undefined): void { - this.update({ userOptIn: state }); + this.update({ + smartTransactionsState: { + ...this.state.smartTransactionsState, + userOptIn: state, + }, + }); } updateSmartTransaction(smartTransaction: SmartTransaction): void { const { chainId } = this.config; - const { smartTransactions } = this.state; + const { smartTransactionsState } = this.state; + const { smartTransactions } = smartTransactionsState; const currentSmartTransactions = smartTransactions[chainId]; const currentIndex = currentSmartTransactions?.findIndex( (st) => st.uuid === smartTransaction.uuid, @@ -176,12 +191,15 @@ export default class SmartTransactionsController extends BaseController< const history = [snapshot]; const historifiedSmartTransaction = { ...smartTransaction, history }; this.update({ - smartTransactions: { - ...this.state.smartTransactions, - [chainId]: [ - ...this.state.smartTransactions?.[chainId], - historifiedSmartTransaction, - ], + smartTransactionsState: { + ...smartTransactionsState, + smartTransactions: { + ...smartTransactionsState.smartTransactions, + [chainId]: [ + ...smartTransactionsState.smartTransactions?.[chainId], + historifiedSmartTransaction, + ], + }, }, }); return; @@ -202,19 +220,24 @@ export default class SmartTransactionsController extends BaseController< } this.update({ - smartTransactions: { - ...this.state.smartTransactions, - [chainId]: this.state.smartTransactions[chainId].map((item, index) => { - return index === currentIndex - ? { ...item, ...smartTransaction } - : item; - }), + smartTransactionsState: { + ...smartTransactionsState, + smartTransactions: { + ...smartTransactionsState.smartTransactions, + [chainId]: smartTransactionsState.smartTransactions[chainId].map( + (item, index) => { + return index === currentIndex + ? { ...item, ...smartTransaction } + : item; + }, + ), + }, }, }); } async updateSmartTransactions() { - const { smartTransactions } = this.state; + const { smartTransactions } = this.state.smartTransactionsState; const { chainId } = this.config; const currentSmartTransactions = smartTransactions?.[chainId]; @@ -333,7 +356,7 @@ export default class SmartTransactionsController extends BaseController< nonceLock.releaseLock(); return { ...transaction, - nonce, + nonce: `0x${nonce.toString(16)}`, }; } @@ -446,4 +469,23 @@ export default class SmartTransactionsController extends BaseController< this.configure({ interval }, false, false); } } + + getTransactions({ + addressFrom, + status, + }: { + addressFrom: string; + status: SmartTransactionStatuses; + }): SmartTransaction[] { + const { smartTransactions } = this.state.smartTransactionsState; + const { chainId } = this.config; + const currentSmartTransactions = smartTransactions?.[chainId]; + if (!currentSmartTransactions || currentSmartTransactions.length === 0) { + return []; + } + + return currentSmartTransactions.filter((stx) => { + return stx.status === status && stx.txParams?.from === addressFrom; + }); + } }