Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add detection params (userAddress, chainId) and remove duplicate source of truth #636

Merged
merged 12 commits into from
Nov 30, 2021

Conversation

wachunei
Copy link
Member

@wachunei wachunei commented Nov 22, 2021

Description

  • REMOVED

    • [BREAKING] Both collectibles and collectibleContracts are removed from CollectiblesController state.
  • FIXED:

    • [BREAKING] Change auto detection from boolean to an object containing address and chainId that was used to autodetect.

Checklist

  • Tests are included if applicable
  • Any added code is fully documented

Issue

Related MetaMask/metamask-mobile#3335

@wachunei wachunei changed the title Add detection params (address, chainId) to collectibles autodetection Add detection params (address, chainId) and remove duplicate source of truth Nov 24, 2021
@wachunei wachunei marked this pull request as ready for review November 25, 2021 15:35
@wachunei wachunei requested a review from a team as a code owner November 25, 2021 15:35
@@ -353,10 +365,7 @@ export class CollectibleDetectionController extends BaseController<
}

/* istanbul ignore else */
if (
!ignored &&
requestedSelectedAddress === this.config.selectedAddress
Copy link
Member

@gantunesr gantunesr Nov 26, 2021

Choose a reason for hiding this comment

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

Interesting, so this condition was only added on the CollectibleDetectionController and not in the CollectiblesController

Copy link
Member

@gantunesr gantunesr left a comment

Choose a reason for hiding this comment

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

Left some small comments

src/assets/CollectiblesController.ts Outdated Show resolved Hide resolved
src/assets/CollectiblesController.ts Outdated Show resolved Hide resolved
});
collectiblesController.configure({ selectedAddress });
Copy link
Contributor

Choose a reason for hiding this comment

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

I know these are unit tests so we don't need to test the integration points with other Controllers but I generally like to use the upstream method where the piece of state we're subscribed to actually changes (in this case it would be preferences.setSelectedAddress(selectedAddress)). I think it makes our network of assumptions safer but I'm open to being convinced otherwise! Thoughts @Gudahtt @wachunei @gantunesr

Copy link
Member

Choose a reason for hiding this comment

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

If we wanted to test this robustly we'd do both. I'd rather us migrate to using the new base controller than waste our time doing that though, because we don't really want configure to be public API like this.

Following your suggestion would be better at least in that it'd be more compatible with BaseControllerV2 when we do migrate.

expect(collectiblesController.state.ignoredCollectibles).toHaveLength(0);
collectiblesController.removeAndIgnoreCollectible(
'0x1d963688fe2209a98db35c67a041524822cf04ff',
'0x1d963688FE2209A98dB35C67A041524822Cf04ff',
Copy link
Contributor

Choose a reason for hiding this comment

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

just curious why was the checksum change here necessary?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not really, I did it without noticing 😅

@@ -131,6 +132,7 @@ export interface ApiCollectibleCollection {
export interface CollectibleDetectionConfig extends BaseConfig {
interval: number;
networkType: NetworkType;
chainId: `0x${string}` | `${number}` | number;
Copy link
Contributor

@adonesky1 adonesky1 Nov 26, 2021

Choose a reason for hiding this comment

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

Whoa! I didn't know you could do string interpolated types! So cool

return;
}

await safelyExecute(async () => {
const apiCollectibles = await this.getOwnerCollectibles();
const apiCollectibles = await this.getOwnerCollectibles(selectedAddress);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not understanding what we achieve by getting selectedAddress in detectCollectibles and passing it in to getOwnerCollectibles rather than just pulling selectedAddress off config in getOwnerCollectibles?

Copy link
Member Author

Choose a reason for hiding this comment

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

We just want to avoid grabbing it in different places to make sure it does not change along the execution of the procedure

Copy link
Contributor

@adonesky1 adonesky1 left a comment

Choose a reason for hiding this comment

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

I think in general I don't like the pattern of replacing undefined with an empty array because it maintains the default value of the collectibles and collectibleContracts subset state values. I think it ends up causing more confusion. Open to be convinced otherwise though!

src/assets/CollectibleDetectionController.test.ts Outdated Show resolved Hide resolved
src/assets/CollectiblesController.test.ts Outdated Show resolved Hide resolved
collectiblesController.state.allCollectibleContracts[selectedAddress][
chainId
],
).toHaveLength(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we remove the key rather than just remove the item from the array when there are no more left for the address/chainId combo?

Copy link
Member

Choose a reason for hiding this comment

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

I agree that this would be nicer, so that the behaviour after adding and removing a collectible matches the initial behaviour. Leaves us with less cases to test, and it's simpler for anyone using this state. I don't want to block on it though.

src/assets/CollectiblesController.ts Outdated Show resolved Hide resolved
src/assets/CollectiblesController.ts Outdated Show resolved Hide resolved
src/assets/CollectiblesController.ts Outdated Show resolved Hide resolved
src/assets/CollectiblesController.ts Outdated Show resolved Hide resolved
@wachunei
Copy link
Member Author

I updated the expect arguments to be assertive (removed optional chaining when we expect a value, removed default []) and the expectations to match this change.

About this:

Should we remove the key rather than just remove the item from the array when there are no more left for the address/chainId combo?

I think it makes sense to prune empty nodes, is it something we do usually? I'd defer decision to you guys that are more familiar with controllers conventions.

wachunei added a commit that referenced this pull request Nov 30, 2021
adonesky1
adonesky1 previously approved these changes Nov 30, 2021
Copy link
Contributor

@adonesky1 adonesky1 left a comment

Choose a reason for hiding this comment

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

LGTM

@Gudahtt
Copy link
Member

Gudahtt commented Nov 30, 2021

So these "detection params", what purpose do these serve? Is this so that the chainID/address at time of detection is preserved, so that the NFT is assigned correctly if the user switches accounts/networks while the detection was still being processed? I didn't see the problem this was meant to solve explained anywhere.

@wachunei
Copy link
Member Author

Yes, exactly that

);
await this.addCollectible(address, token_id, collectibleMetadata, {
userAddress: selectedAddress,
chainId: chainId as string,
Copy link
Member

Choose a reason for hiding this comment

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

Nit: We should not need to cast here. If it's possible for this to be something other than a string, we need to deal with that here. If it's not, then the type is wrong and we should fix that instead.

Copy link
Member

Choose a reason for hiding this comment

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

The chain ID normalization above is responsible for this. It is guaranteed to be a string here but the normalization is done in a way TypeScript's inference is having trouble with. I've just prototyped a solution that I can prepare as a follow up PR later.

Copy link
Member

Choose a reason for hiding this comment

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

Basically it's to move the normalization to a utility function, and adjust the conditions to help TypeScript's inference along a bit better, and add a "throw" case for invalid chain IDs.

Copy link
Member Author

Choose a reason for hiding this comment

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

I see, this type and normalization is also present in the GasFeeController, so we can use that util there.

this.configure({ networkType: provider.type });
this.configure({
networkType: provider.type,
chainId: provider.chainId as CollectibleDetectionConfig['chainId'],
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Ideally we'd parse this here to guarantee that the chain ID is the expected type, rather than cast. Or propagate this new chain ID type into the network controller as well. I guess we can do that later.

src/assets/CollectibleDetectionController.ts Outdated Show resolved Hide resolved
@@ -228,6 +229,7 @@ export class CollectibleDetectionController extends BaseController<
this.defaultConfig = {
interval: DEFAULT_INTERVAL,
networkType: MAINNET,
chainId: '1',
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I don't object to doing this for now, since the default networkType is MAINNET already, so this is a pre-existing issue. But we shouldn't be setting a default network at all, we can get the true current network from the network controller by passing in a getNetworkState function to the constructor.

This could lead to bugs where something runs initially before the first network state update, and uses the wrong network.

@Gudahtt
Copy link
Member

Gudahtt commented Nov 30, 2021

Overall looks good! I'm very glad to see that duplicate state removed. It would have been better to do this in two separate PRs, but what's done is done. I can take another look when conflicts are resolved.

Co-authored-by: Mark Stacey <markjstacey@gmail.com>
@wachunei
Copy link
Member Author

@Gudahtt Conflicts are resolved 👌

wachunei added a commit that referenced this pull request Nov 30, 2021
Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

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

LGTM!

@wachunei wachunei changed the title Add detection params (address, chainId) and remove duplicate source of truth Add detection params (userAddress, chainId) and remove duplicate source of truth Nov 30, 2021
@wachunei wachunei merged commit 7754dd7 into main Nov 30, 2021
@wachunei wachunei deleted the fix/collectibles-autodetect branch November 30, 2021 22:21
MajorLift pushed a commit that referenced this pull request Oct 11, 2023
…ce of truth (#636)

Co-authored-by: Alex Donesky <adonesky@gmail.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
MajorLift pushed a commit that referenced this pull request Oct 11, 2023
…ce of truth (#636)

Co-authored-by: Alex Donesky <adonesky@gmail.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants