-
-
Notifications
You must be signed in to change notification settings - Fork 242
feat: add multichain-account-service
(readonly)
#6141
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
Conversation
8ffe4ea
to
7c23474
Compare
No dependency changes detected. Learn more about Socket for GitHub. 👍 No dependency changes detected in pull request |
9755a66
to
51f4404
Compare
const accounts: Bip44Account<InternalAccount>[] = []; | ||
|
||
for (const account of this.messenger.call( | ||
'AccountsController:listMultichainAccounts', |
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 might be worth adding a comment saying what this actually does (until such time as the action is changed)
i.e. it fetches all internal accounts
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.
Agreed, some JS doc would be good here.
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.
Just added a small comment explaining what the action does, and also added a comment to explain that we should probably rename this at some point!
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.
Fixed here: de60d19
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 work looks good to me, I left some comments/suggestions
packages/multichain-account-controller/src/MultichainAccountController.ts
Outdated
Show resolved
Hide resolved
packages/multichain-account-controller/src/MultichainAccountController.ts
Outdated
Show resolved
Hide resolved
packages/multichain-account-controller/src/MultichainAccountController.ts
Outdated
Show resolved
Hide resolved
packages/multichain-account-controller/src/MultichainAccountController.ts
Outdated
Show resolved
Hide resolved
Co-authored-by: cryptodev-2s <[email protected]>
const entropySources = []; | ||
for (const keyring of keyrings) { | ||
if (keyring.type === (KeyringTypes.hd as string)) { | ||
entropySources.push(keyring.metadata.id); | ||
} | ||
} |
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: I think you can use a reduce here and condense this code block.
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.
Yup, I did refactor this a bit indeed 😅 I saw that when handling KeyringController:stateChange
, so it should be simpler now.
@ccharly What do you think about renaming this to a Service instead of a Controller? |
Well, that was our initial idea with @danroc actually! 😄 I just thought that But yes, this "controller" will remain stateless, so Just to be clear, this controller is only using "internal data" ( |
Yes, that aligns well with our current definition of what a Service could be. Glad we’re on the same page, feel free to proceed with the rename. |
multichain-account-controller
(readonly)multichain-account-service
(readonly)
Doing this defensive check sounds a bit too much to me given that |
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.
Looks great! Just some minor comments.
// TODO: For now, we to every `KeyringController` state change to detect when | ||
// new entropy sources/SRPs are being added. Having a dedicated event when | ||
// new keyrings are added would make this more efficient. | ||
this.#messenger.subscribe('KeyringController:stateChange', (state) => { | ||
this.#setMultichainAccountWallets(state.keyrings); | ||
}); |
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.
You mention having a dedicated event, but there's already another way to do this that's more efficient.
The subscribe
method takes a third argument, a function that works in spirit similar to input selectors in Redux (that is, they should be simple and only return a single property of the state object). This function should return the part of state that you are interested in observing.
What about this:
// TODO: For now, we to every `KeyringController` state change to detect when | |
// new entropy sources/SRPs are being added. Having a dedicated event when | |
// new keyrings are added would make this more efficient. | |
this.#messenger.subscribe('KeyringController:stateChange', (state) => { | |
this.#setMultichainAccountWallets(state.keyrings); | |
}); | |
this.#messenger.subscribe( | |
'KeyringController:stateChange', | |
(keyringsFromState) => { | |
this.#setMultichainAccountWallets(keyringsFromState); | |
}, | |
selectKeyringControllerKeyrings, | |
); |
And then above the class MultichainAccountService
line, you could add:
/**
* Select keyrings from keyring controller state.
*
* @param state - The keyring controller state.
* @returns The keyrings.
*/
function selectKeyringControllerKeyrings(state: KeyringControllerState) {
return state.keyrings;
}
Because the entire keyrings
array is changed if a new keyring is added or removed, it will detect that state.keyrings
is a new object reference and your subscription function will be called. And if no keyrings are added or removed, your subscription function will not be called.
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.
Sounds like a good idea! I always forgot we have built-in selectors for controllers too! 🙈
Let me do 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.
Fixed here: 7399ee3
packages/multichain-account-service/src/providers/BaseAccountProvider.test.ts
Outdated
Show resolved
Hide resolved
isAccountCompatible(account: InternalAccount): boolean { | ||
return ( | ||
account.type === EthAccountType.Eoa && | ||
account.metadata.keyring.type === (KeyringTypes.hd as string) |
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.
Is this type assertion needed?
account.metadata.keyring.type === (KeyringTypes.hd as string) | |
account.metadata.keyring.type === KeyringTypes.hd |
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.
Similar answer: #6141 (comment)
isAccountCompatible(account: InternalAccount): boolean { | ||
return ( | ||
account.type === SolAccountType.DataAccount && | ||
account.metadata.keyring.type === (KeyringTypes.snap as string) |
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.
Is this type assertion needed?
account.metadata.keyring.type === (KeyringTypes.snap as string) | |
account.metadata.keyring.type === KeyringTypes.snap |
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.
So, it's not "truly needed" but we do get a warning if we're not doing it that way, cause account.metadata.keyring.type
is actually a string
and we compare it with an enum
value... I'm also a bit surprised by this TBH, but I have seen this same warning in some AccountsController
comparisons too:
The two values in this comparison do not have a shared enum type.eslint[@typescript-eslint/no-unsafe-enum-comparison](https://typescript-eslint.io/rules/no-unsafe-enum-comparison)
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.
Oh weird. For some reason I wasn't getting that warning locally. But I do know about it. Never mind then :)
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: Are these tests for tests? :)
Typically if a test helper needs tests it indicates it's too complex. Maybe we can rely on the fact it is being tested indirectly and so we don't need this file?
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.
Actually, I can probably remove this yes. I had to add a tests because some MockAccountBuilder
methods are not yet in use, but they will be used in a future PR. For the moment I guess I can just remove them, thus, they should be covered "implicitly" yes 👍
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.
Fixed here: 18a6358
Co-authored-by: Elliot Winkler <[email protected]>
Co-authored-by: Elliot Winkler <[email protected]>
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.
Bug: Function Fails When Options Undefined
The isBip44Account
function throws a TypeError if account.options
is undefined, as it directly accesses account.options.entropy
. This prevents the intended behavior of returning false
and logging a warning. Use optional chaining (account.options?.entropy
) to safely access the property.
packages/multichain-account-service/src/providers/BaseAccountProvider.ts#L26-L29
core/packages/multichain-account-service/src/providers/BaseAccountProvider.ts
Lines 26 to 29 in 7399ee3
): account is Bip44Account<Account> { | |
if ( | |
!account.options.entropy || | |
account.options.entropy.type !== KeyringAccountEntropyTypeOption.Mnemonic |
Was this report helpful? Give feedback by reacting with 👍 or 👎
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
Introducing a new service to support multichain accounts/wallets.
References
N/A
Changelog
N/A
Checklist