Skip to content

Commit 57dc578

Browse files
authored
fix: Improve state management (#353)
1 parent b487267 commit 57dc578

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

src/SmartTransactionsController.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,79 @@ describe('SmartTransactionsController', () => {
460460
} as NetworkState);
461461
expect(checkPollSpy).toHaveBeenCalled();
462462
});
463+
464+
it('calls "ensureUniqueSmartTransactions" on network change if it is a new chainId', () => {
465+
const { smartTransactionsState } = smartTransactionsController.state;
466+
const smartTransactionsForChainId = createStateAfterSuccess();
467+
smartTransactionsForChainId.push({
468+
// Duplicate a smart transaction with the same uuid.
469+
...smartTransactionsForChainId[0],
470+
status: 'pending',
471+
});
472+
smartTransactionsController.update({
473+
smartTransactionsState: {
474+
...smartTransactionsState,
475+
smartTransactions: {
476+
[ChainId.mainnet]:
477+
smartTransactionsForChainId as SmartTransaction[],
478+
},
479+
},
480+
});
481+
smartTransactionsController.config.chainId = ChainId.sepolia;
482+
networkListener({
483+
providerConfig: {
484+
chainId: ChainId.mainnet,
485+
type: 'rpc',
486+
ticker: 'ETH',
487+
},
488+
selectedNetworkClientId: 'networkClientId',
489+
networkConfigurations: {},
490+
networksMetadata: {},
491+
} as NetworkState);
492+
const uniqueSmartTransactionsForChainId =
493+
smartTransactionsController.state.smartTransactionsState
494+
.smartTransactions[ChainId.mainnet];
495+
expect(uniqueSmartTransactionsForChainId).toHaveLength(1);
496+
expect(uniqueSmartTransactionsForChainId).toStrictEqual([
497+
smartTransactionsForChainId[0],
498+
]);
499+
});
500+
501+
it('does not call "ensureUniqueSmartTransactions" on network change for the same chainId', () => {
502+
const { smartTransactionsState } = smartTransactionsController.state;
503+
const smartTransactionsForChainId = createStateAfterSuccess();
504+
smartTransactionsForChainId.push({
505+
// Duplicate a smart transaction with the same uuid.
506+
...smartTransactionsForChainId[0],
507+
status: 'pending',
508+
});
509+
smartTransactionsController.update({
510+
smartTransactionsState: {
511+
...smartTransactionsState,
512+
smartTransactions: {
513+
[ChainId.mainnet]:
514+
smartTransactionsForChainId as SmartTransaction[],
515+
},
516+
},
517+
});
518+
networkListener({
519+
providerConfig: {
520+
chainId: ChainId.mainnet,
521+
type: 'rpc',
522+
ticker: 'ETH',
523+
},
524+
selectedNetworkClientId: 'networkClientId',
525+
networkConfigurations: {},
526+
networksMetadata: {},
527+
} as NetworkState);
528+
const currentSmartTransactionsForChainId =
529+
smartTransactionsController.state.smartTransactionsState
530+
.smartTransactions[ChainId.mainnet];
531+
expect(currentSmartTransactionsForChainId).toHaveLength(2);
532+
expect(currentSmartTransactionsForChainId).toStrictEqual(
533+
smartTransactionsForChainId,
534+
);
535+
});
463536
});
464537

465538
describe('checkPoll', () => {

src/SmartTransactionsController.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,16 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
183183
this.getNetworkClientById = getNetworkClientById;
184184

185185
this.initializeSmartTransactionsForChainId();
186+
this.#ensureUniqueSmartTransactions();
186187

187188
onNetworkStateChange(({ providerConfig: newProvider }) => {
188189
const { chainId } = newProvider;
190+
const isNewChainId = chainId !== this.config.chainId;
189191
this.configure({ chainId });
190192
this.initializeSmartTransactionsForChainId();
193+
if (isNewChainId) {
194+
this.#ensureUniqueSmartTransactions();
195+
}
191196
this.checkPoll(this.state);
192197
this.ethQuery = new EthQuery(provider);
193198
});
@@ -238,6 +243,35 @@ export default class SmartTransactionsController extends StaticIntervalPollingCo
238243
}
239244
}
240245

246+
// We fixed having duplicate smart transactions with the same uuid in a very rare edge case.
247+
// This function resolves it for a few users who have this issue and once we see in logs
248+
// that everything is fine, we can remove this function.
249+
#ensureUniqueSmartTransactions() {
250+
const { smartTransactions } = this.state.smartTransactionsState;
251+
const chainId = ChainId.mainnet; // Smart Transactions are only available on Ethereum mainnet at the moment.
252+
const smartTransactionsForChainId = smartTransactions[chainId];
253+
if (!smartTransactionsForChainId) {
254+
return;
255+
}
256+
const uniqueUUIDs = new Set();
257+
const uniqueSmartTransactionsForChainId = [];
258+
for (const transaction of smartTransactionsForChainId) {
259+
if (!uniqueUUIDs.has(transaction.uuid)) {
260+
uniqueUUIDs.add(transaction.uuid);
261+
uniqueSmartTransactionsForChainId.push(transaction);
262+
}
263+
}
264+
this.update({
265+
smartTransactionsState: {
266+
...this.state.smartTransactionsState,
267+
smartTransactions: {
268+
...smartTransactions,
269+
[chainId]: uniqueSmartTransactionsForChainId,
270+
},
271+
},
272+
});
273+
}
274+
241275
async poll(interval?: number): Promise<void> {
242276
const { chainId, supportedChainIds } = this.config;
243277
interval && this.configure({ interval }, false, false);

0 commit comments

Comments
 (0)