Skip to content

key tokens by chainId#10510

Merged
brad-decker merged 1 commit intodevelopfrom
key-tokens-by-chain-id
Feb 26, 2021
Merged

key tokens by chainId#10510
brad-decker merged 1 commit intodevelopfrom
key-tokens-by-chain-id

Conversation

@brad-decker
Copy link
Copy Markdown
Contributor

@brad-decker brad-decker commented Feb 23, 2021

Progresses: #8668
fixes #10518

Explanation: Tokens are keyed by providerType which is 'rpc' for all custom networks. Adding a token to one custom network replicates it across all custom networks. This is not only inappropriate but also could lead to issues where a token doesn't exist at the same contract address across chains.

This PR aims to replicate the user's current experience but silently move the 'rpc' tokens into keys by chainId. It also merges chainIds for the five pre-programmed chains with any custom networks that share those chainIds, so mainnet and custom network with chainId 0x1 will have the same tokens.

after the migration, any new tokens added per chain will be specific to that chain, and removing tokens from custom networks will not remove them from all.

@brad-decker brad-decker force-pushed the key-tokens-by-chain-id branch 2 times, most recently from 6163af0 to a475727 Compare February 24, 2021 18:15
@brad-decker brad-decker marked this pull request as ready for review February 24, 2021 18:29
@brad-decker brad-decker requested a review from a team as a code owner February 24, 2021 18:29
@metamaskbot
Copy link
Copy Markdown
Collaborator

Builds ready [a475727]
Page Load Metrics (591 ± 21 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint46716184
domContentLoaded5337005904421
load5347025914421
domInteractive5337005894421

*/
_subscribeProviderType() {
this.network.providerStore.subscribe(() => {
_subscribeToNetworkDidChange() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, this change is functionally equivalent, as the NETWORK_DID_CHANGE event is only emitted at the time that the providerStore is updated.

@@ -671,8 +672,8 @@ export default class PreferencesController {
*
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the code comment for this method could be slightly modified. Subscription to NETWORK_DID_CHANGE events or something like that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reworded comment in the latest commit

const newAccountHiddenTokens = {};

if (accountTokens && Object.keys(accountTokens).length > 0) {
for (const account of Object.keys(accountTokens)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think the account variable might be more appropriately name address or accountAddress, which better conveys what that variable is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in the latest

break;
}
}
if (accountTokens[account][NETWORK_TYPE_RPC]) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to put this in its own if block instead of add it as a case to the above switch?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, because you need the above for loop to complete before the below logic can properly migrate account tokens for custom rpcs that share a chain id with one of the default networks

) {
newAccountTokens[account][detail.chainId] = uniqBy(
[
...newAccountTokens[account][detail.chainId],
Copy link
Copy Markdown
Contributor

@danjm danjm Feb 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this logic, it seems the following could happen:

  • user currently has token ABC on mainnet
  • user currently has token DEF on a custom rpc X, which has the same chainId as mainnet
  • user currently has tokens GHI on a custom rpc Y, which has a different chainId than mainnet
  • so currently, on mainnet, the user will only see ABC, but on both X and Y the user will see both DEF and GHI (because all tokens are stored by provider type, and X and Y have the same provider type NETWORK_TYPE_RPC)
  • after this migration, the user will (as desired) continue to see ABC on mainnet and will see ABC on X (via ...newAccountTokens[account][detail.chainId]), and (as desired) will see DEF on mainnet and X, BUT will also see GHI on mainnet and X (via ...accountTokens[account][NETWORK_TYPE_RPC])

I think we should avoid this if possible, but I am not sure that it is possible...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or am I misunderstanding somehow?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am not misunderstanding, the only way to achieve a distinction of NETWORK_TYPE_RPC tokens by chainId would be to check on chain data via a network request. That is, we could check if the user has any of the token each of the networks with the chain id. Not sure if this is feasbile within our migration or desirable given network load.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we need to add precision to what we are keying by here: key by a combination of provider type and chain id

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key by a combination of provider type and chain id

This would result in the following:

  • the migration would not change the current tokens of default networks
  • all custom networks would continue to have all the tokens they already do
  • custom networks and default networks that share chainIds would NOT have each others tokens as a result of the migration
  • post migration, newly added tokens will be added network by network, and even if two networks share a chainId, adding a token to one will not add a token to another (unless we add further code that ensures that)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might suggest a simpler solution that gets more to the heart of #8668 (treating custom networks with the chainId 0x1 as mainnet) - For this migration prefer the tokens listed under mainnet for '0x1'. So the following would happen:

  1. For all custom networks the user has added that don't share a chainId with a default MetaMask chain, they will continue to have all tokens listed under 'rpc' provider type.
  2. For all default networks the user tokens will be unchanged.
  3. For any custom network that shares a chainId with a default network, they will inherit the default network's tokens and those will be shared across them.

If we want to preserve the ability to have different tokens on different networks (which is sort of going against the spirit of #8668 in my opinion) that share the same chainId, then I'm fine with @danjm 's suggestion.

@MetaMask/extension-devs anyone else have opinions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am not misunderstanding, the only way to achieve a distinction of NETWORK_TYPE_RPC tokens by chainId would be to check on chain data via a network request. That is, we could check if the user has any of the token each of the networks with the chain id. Not sure if this is feasbile within our migration or desirable given network load.

i'd like to point out that we don't currently do this, any token a user adds for a custom network is added to all custom networks. I think it's out of scope to consider this for this migration and puts the extension in a better place to handle it in the future by isolating tokens added per chain.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brad-decker The simpler solution you suggested sounds good. One remaining question about this case:

For any custom network that shares a chainId with a default network, they will inherit the default network's tokens and those will be shared across them.

Will such custom networks also continue to have all other tokens that are currently under the rpc provider type. Or are you suggesting that, after the migration, these custom networks will only have the tokens that are from the default network they share a chainId with?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the following current state:

const frequentRpcListDetail = [
	{
		chainId: '0x1',
        networkName: 'mainnet custom endpoint'
	},
    {
		chainId: '0xabc',
        networkName: 'non default network'
    }
];
const accounTokens = {
  '0x1111': {
    'mainnet': ['X', 'Y', 'Z'],
    'rpc': ['A', 'B', 'C', 'Z'],
   }
};

the resulting new structure of accountTokens would be:

accounTokens = {
  '0x1111': {
    '0x1': ['X', 'Y', 'Z'],
    '0xabc': ['A', 'B', 'C', 'Z'],
   }
};

so previously the user connected to their custom mainnet endpoint and added 'Z' token, which is also in the default mainnet. presumably for the purposes of tracking that mainnet token on their custom network. They also added 'A', 'B', 'C' tokens for the '0xabc' chain. After the migration the custom network and mainnet will have identical token lists and will remain in sync, including hiding tokens. The custom network with a non default network chain id will remain in the same state it was in prior to the migration with the added benefit that hiding tokens on that network will not hide the tokens elsewhere and adding new tokens to it will not add them elsewhere (for custom RPCs anyways)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic was implemented in the latest commit

) {
newAccountHiddenTokens[account][detail.chainId] = uniqBy(
[
...newAccountHiddenTokens[account][detail.chainId],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is subject to similar concerns that I raised above.

@brad-decker brad-decker force-pushed the key-tokens-by-chain-id branch from a475727 to 7291990 Compare February 25, 2021 19:18
@brad-decker brad-decker requested a review from danjm February 25, 2021 19:19
@metamaskbot
Copy link
Copy Markdown
Collaborator

Builds ready [7291990]
Page Load Metrics (667 ± 49 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint4711667199
domContentLoaded56596266610149
load56796466710149
domInteractive56596266610149

Copy link
Copy Markdown
Contributor

@danjm danjm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest changes look good. Tests look good. Approved.

@brad-decker brad-decker merged commit caa32d8 into develop Feb 26, 2021
@brad-decker brad-decker deleted the key-tokens-by-chain-id branch February 26, 2021 15:40
@github-actions github-actions bot locked and limited conversation to collaborators Feb 26, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom Token added appears in all custom RPC Network

3 participants