-
-
Notifications
You must be signed in to change notification settings - Fork 210
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
upgrade TokenRatesController to BaseControllerV2 #4314
upgrade TokenRatesController to BaseControllerV2 #4314
Conversation
|
||
// This interface was created before this ESLint rule was added. | ||
// Convert to a `type` in a future major version. | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions | ||
export interface ContractExchangeRates { | ||
[address: string]: number | undefined; | ||
[address: string]: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
undefined
is removed, because it is not a json type! We need to fix on the consumer side, in case this will cause an error, where it is consumed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could either delete
keys that have an undefined
value, or accept null
instead of undefined
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also you can consider update interface to type
currentChainId, | ||
currentTicker, | ||
currentAddress, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Would it be possible to substitute these with messenger calls? I believe we can obtain the current chain id from NetworkController
, and the current selected address from AccountsController
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sense.
I've removed the currentChainId
, currentTicker
and currentAddress
and now currentChainId
and currentTicker
are assigned form messenger network state and selectedAddress
from PreferencesController state.
this.#interval = interval; | ||
this.#chainId = currentChainId; | ||
this.#ticker = currentTicker; | ||
this.#selectedAddress = currentAddress; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the selected address as a class variable here means that we also need to keep this in sync. Perhaps it would be better to always take the fresh value from AccountsController
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sense.
TokenRatesController uses PreferencesController state to manage the selectedAddress. So for now, initial selected address will be assigned from the same to be consistent. But I believe that the selectedAddress has to be pointing to AccountsController rather than PreferencesController. I'll open up a separate ticket to make those changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like using AccountsController to get the selected address will be addressed in #4219.
this.#tokenPricesService = tokenPricesService; | ||
this.#disabled = disabled; | ||
this.#interval = interval; | ||
this.#chainId = currentChainId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly to #selectedAddress
, would it be easier to take this value from NetworkController
instead of storing it in a class variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, rather than referencing outside variables each time when we need selectedAddress within the class, accessing private class / instance variable will be easier and faster.
And I think, global truth for selectedAddress has to be from AccountsController.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern seems okay to me. In fact it may be advantageous to use private properties to cache values like this to mitigate synchronization issues. Like, if we have to pull a bunch of values from a bunch of controllers at the start of a polling iteration it might be better to do that all in one go and then cache those values rather than fetch them at various points during that iteration (which is what we'd have to do if we didn't use private properties, I believe).
Now the default value for |
|
||
// @ts-expect-error Intentionally incomplete state | ||
controllerEvents.tokensStateChange({ | ||
triggerTokensStateChange({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this test we want to Intentionally test incomplete state ? in this case we shouldn't be adding getDefaultTokensState ? same for the above test where it has been removed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, the messenger publish expects complete state of the TokensControllerState!
@@ -152,13 +183,25 @@ async function getCurrencyConversionRate({ | |||
} | |||
} | |||
|
|||
const metadata = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to align with other controllers this can be tokenRatesControllerMetadata
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
// This interface was created before this ESLint rule was added. | ||
// Convert to a `type` in a future major version. | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions | ||
export interface ContractExchangeRates { | ||
[address: string]: number | undefined; | ||
[address: string]: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also you can consider update interface to type
@@ -111,9 +120,31 @@ enum PollState { | |||
// This interface was created before this ESLint rule was added. | |||
// Convert to a `type` in a future major version. | |||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the eslint disable can be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
AllowedEvents['type'] | ||
>; | ||
|
||
export type TokenRatesControllerStateChangeEvent = ControllerStateChangeEvent< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this should be above TokenRatesControllerMessenger
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
chainId: '0x1', | ||
selectedAddress: defaultSelectedAddress, | ||
it('should set default state', async () => { | ||
await withController({}, async ({ controller }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be await withController(async ({ controller }) => {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
this.#interval = interval; | ||
this.#chainId = currentChainId; | ||
this.#ticker = currentTicker; | ||
this.#selectedAddress = currentAddress; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like using AccountsController to get the selected address will be addressed in #4219.
mockGetNetworkClientById.mockImplementation(handler); | ||
}, | ||
callActionSpy, | ||
triggerPreferencesStateChange: (state: PreferencesState) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: What are your thoughts on having tests use the messenger directly to do whatever they want rather than wrapping each of the actions in a function? It is already pretty short to say messenger.publish('whatever')
in a test, so it doesn't seem that we are saving that many characters here. Dropping these wrappers would also simplify withController
so that it is more copy-and-pasteable across files.
Oof I didn't mean to request changes, sorry. |
TokensControllerGetStateAction, | ||
TokensControllerStateChangeEvent, | ||
TokensControllerState, | ||
} from './TokensController'; | ||
|
||
/** | ||
* @type Token |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we don't have jsdoc for aggregators
, hasBalanceError
, isErc721
, name
. This isn't due to any change introduced by this PR, but it would be nice to address this while we're doing this upgrade.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have noticed many types are missing some properties definition, I don't know if can force this with an eslint rule
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a starting point:
* @property aggregators - An array containing the token's aggregators
* @property hasBalanceError - 'true' if getting the balance of an ERC-20 token resulted in an error
* @property isErc721 - 'true' if the token is an NFT
* @property name - Name of the token
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cryptodev-2s I'm sure there are jsdoc eslint rules that are supposed to do that. I'll write up a ticket for enabling them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like we're moving away from jsdoc comments for types, since annotating each property individually gives the user better access to the comments, especially when hovering on the property.
(e.g. see https://github.com/MetaMask/core/pull/4286/files#diff-ea0aa37793484e278bd59970b7a6ce8380b75b723b34612081d402fb66261cfdR152-R196, and hover over any search result of "networkConfiguration." (networkConfiguration\.
for regex) in the same file.
For functions, objects etc., we might still want to enforce jsdoc lint rules, so I'll still take a look into configuring this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding an ESLint rule to check for JSDoc'ing properties would be great! I did some initial research into this a while back and didn't find any existing rules but maybe someone has come up with something by now.
…f github.com:MetaMask/core into upgrade-token-rates-controller-to-base-controller-v2
* @property image - Image of the token, url or bit32 image | ||
* @property hasBalanceError - 'true' if there is an error while updating the token balance | ||
* @property isERC721 - 'true' if the token is a ERC721 token | ||
* @property name - Name of the token | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
we can remove this empty space
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more suggestions but this is looking pretty good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Explanation
In this, the TokenRatesController has been upgraded to BaseControllerV2. The upgrade includes TokenRatesController inheriting BaseController v2 instead of BaseController v1. This affects the constructor and the also the way state is updated inside the controller, but it also prompts other changes:
This also includes the changes to the unit tests, so that all the tests uses
withController
pattern.References
Fixes #4076
Changelog
@metamask/assets-controller
Added
TokenRatesController
messenger actionsTokenRatesControllerGetStateAction
TokenRatesController
messenger eventsTokenRatesControllerStateChangeEvent
Changed
TokenRatesController
from BaseController v1 to BaseController v2TokenRatesState
toTokenRatesControllerState
Removed
TokenRatesConfig
typeChecklist