Skip to content

Commit

Permalink
Prevent third party token list polling in the Extension when token de…
Browse files Browse the repository at this point in the history
…tection is OFF (#861)
  • Loading branch information
NiranjanaBinoy committed Jun 29, 2022
1 parent d92bec0 commit 2be6ff9
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/assets/TokenDetectionController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ describe('TokenDetectionController', () => {
const messenger = getTokenListMessenger();
tokenList = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
});
Expand Down
94 changes: 94 additions & 0 deletions src/assets/TokenListController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ const existingState = {
data: sampleMainnetTokensChainsCache,
},
},
preventPollingOnNetworkRestart: false,
};

const outdatedExistingState = {
Expand Down Expand Up @@ -409,6 +410,7 @@ const outdatedExistingState = {
data: sampleMainnetTokensChainsCache,
},
},
preventPollingOnNetworkRestart: false,
};

const expiredCacheExistingState: TokenListState = {
Expand Down Expand Up @@ -465,6 +467,7 @@ const expiredCacheExistingState: TokenListState = {
},
},
},
preventPollingOnNetworkRestart: false,
};

/**
Expand Down Expand Up @@ -502,13 +505,15 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
});

expect(controller.state).toStrictEqual({
tokenList: {},
tokensChainsCache: {},
preventPollingOnNetworkRestart: false,
});

controller.destroy();
Expand All @@ -518,6 +523,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
state: existingState,
Expand Down Expand Up @@ -553,6 +559,7 @@ describe('TokenListController', () => {
data: sampleMainnetTokensChainsCache,
},
},
preventPollingOnNetworkRestart: false,
});

controller.destroy();
Expand All @@ -562,6 +569,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
interval: 100,
messenger,
Expand All @@ -582,6 +590,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
interval: 100,
messenger,
Expand All @@ -606,6 +615,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
interval: 100,
messenger,
Expand All @@ -632,6 +642,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
interval: 100,
messenger,
Expand Down Expand Up @@ -661,6 +672,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
interval: 100,
messenger,
Expand All @@ -684,6 +696,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.localhost,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
interval: 100,
messenger,
Expand All @@ -706,6 +719,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
});
Expand Down Expand Up @@ -742,6 +756,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
interval: 100,
Expand All @@ -764,6 +779,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
state: existingState,
Expand All @@ -790,6 +806,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
});
Expand Down Expand Up @@ -831,6 +848,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
});
Expand All @@ -853,6 +871,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
state: outdatedExistingState,
Expand All @@ -879,6 +898,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
state: expiredCacheExistingState,
Expand Down Expand Up @@ -912,6 +932,7 @@ describe('TokenListController', () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
state: existingState,
Expand Down Expand Up @@ -966,4 +987,77 @@ describe('TokenListController', () => {

controller.destroy();
});

it('should clear the tokenList and tokensChainsCache', async () => {
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.mainnet,
preventPollingOnNetworkRestart: false,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
state: existingState,
});
expect(controller.state).toStrictEqual(existingState);
controller.clearingTokenListData();

expect(controller.state.tokenList).toStrictEqual({});
expect(controller.state.tokensChainsCache).toStrictEqual({});

controller.destroy();
});

it('should update preventPollingOnNetworkRestart and restart the polling on network restart', async () => {
nock(TOKEN_END_POINT_API)
.get(`/tokens/${NetworksChainId.mainnet}`)
.reply(200, sampleMainnetTokenList)
.get(`/tokens/${NetworksChainId.ropsten}`)
.reply(200, { error: 'ChainId 3 is not supported' })
.get(`/tokens/56`)
.reply(200, sampleBinanceTokenList)
.persist();
const messenger = getRestrictedMessenger();
const controller = new TokenListController({
chainId: NetworksChainId.ropsten,
preventPollingOnNetworkRestart: true,
onNetworkStateChange: (listener) => network.subscribe(listener),
messenger,
interval: 100,
});
await controller.start();
network.update({
provider: {
type: 'mainnet',
chainId: NetworksChainId.mainnet,
},
});

expect(controller.state).toStrictEqual({
tokenList: {},
tokensChainsCache: {},
preventPollingOnNetworkRestart: true,
});
controller.updatePreventPollingOnNetworkRestart(false);
expect(controller.state).toStrictEqual({
tokenList: {},
tokensChainsCache: {},
preventPollingOnNetworkRestart: false,
});

network.update({
provider: {
type: 'rpc',
chainId: '56',
},
});
await new Promise<void>((resolve) => setTimeout(() => resolve(), 10));
expect(controller.state.tokenList).toStrictEqual(
sampleTwoChainState.tokenList,
);

expect(controller.state.tokensChainsCache['56'].data).toStrictEqual(
sampleTwoChainState.tokensChainsCache['56'].data,
);

controller.destroy();
});
});
56 changes: 48 additions & 8 deletions src/assets/TokenListController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type TokensChainsCache = {
export type TokenListState = {
tokenList: TokenListMap;
tokensChainsCache: TokensChainsCache;
preventPollingOnNetworkRestart: boolean;
};

export type TokenListStateChange = {
Expand All @@ -59,11 +60,13 @@ type TokenListMessenger = RestrictedControllerMessenger<
const metadata = {
tokenList: { persist: true, anonymous: true },
tokensChainsCache: { persist: true, anonymous: true },
preventPollingOnNetworkRestart: { persist: true, anonymous: true },
};

const defaultState: TokenListState = {
tokenList: {},
tokensChainsCache: {},
preventPollingOnNetworkRestart: false,
};

/**
Expand Down Expand Up @@ -96,16 +99,19 @@ export class TokenListController extends BaseController<
* @param options.cacheRefreshThreshold - The token cache expiry time, in milliseconds.
* @param options.messenger - A restricted controller messenger.
* @param options.state - Initial state to set on this controller.
* @param options.preventPollingOnNetworkRestart - Determines whether to prevent poilling on network restart in extension.
*/
constructor({
chainId,
preventPollingOnNetworkRestart = false,
onNetworkStateChange,
interval = DEFAULT_INTERVAL,
cacheRefreshThreshold = DEFAULT_THRESHOLD,
messenger,
state,
}: {
chainId: string;
preventPollingOnNetworkRestart: boolean;
onNetworkStateChange: (
listener: (networkState: NetworkState) => void,
) => void;
Expand All @@ -123,20 +129,25 @@ export class TokenListController extends BaseController<
this.intervalDelay = interval;
this.cacheRefreshThreshold = cacheRefreshThreshold;
this.chainId = chainId;
this.updatePreventPollingOnNetworkRestart(preventPollingOnNetworkRestart);
this.abortController = new AbortController();
onNetworkStateChange(async (networkState) => {
if (this.chainId !== networkState.provider.chainId) {
this.abortController.abort();
this.abortController = new AbortController();
this.chainId = networkState.provider.chainId;
// Ensure tokenList is referencing data from correct network
this.update(() => {
return {
...this.state,
tokenList: this.state.tokensChainsCache[this.chainId]?.data || {},
};
});
await this.restart();
if (this.state.preventPollingOnNetworkRestart) {
this.clearingTokenListData();
} else {
// Ensure tokenList is referencing data from correct network
this.update(() => {
return {
...this.state,
tokenList: this.state.tokensChainsCache[this.chainId]?.data || {},
};
});
await this.restart();
}
}
});
}
Expand Down Expand Up @@ -218,6 +229,7 @@ export class TokenListController extends BaseController<

this.update(() => {
return {
...this.state,
tokenList,
tokensChainsCache,
};
Expand Down Expand Up @@ -264,6 +276,7 @@ export class TokenListController extends BaseController<
};
this.update(() => {
return {
...this.state,
tokenList,
tokensChainsCache: updatedTokensChainsCache,
};
Expand Down Expand Up @@ -292,6 +305,33 @@ export class TokenListController extends BaseController<
}
return null;
}

/**
* Clearing tokenList and tokensChainsCache explicitly.
*/
clearingTokenListData(): void {
this.update(() => {
return {
...this.state,
tokenList: {},
tokensChainsCache: {},
};
});
}

/**
* Updates preventPollingOnNetworkRestart from extension.
*
* @param shouldPreventPolling - Determine whether to prevent polling on network change
*/
updatePreventPollingOnNetworkRestart(shouldPreventPolling: boolean): void {
this.update(() => {
return {
...this.state,
preventPollingOnNetworkRestart: shouldPreventPolling,
};
});
}
}

export default TokenListController;

0 comments on commit 2be6ff9

Please sign in to comment.