-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: Add Multichain API to Flask #14756
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
base: main
Are you sure you want to change the base?
Conversation
…/caip-25-refactor
Review the following changes in direct dependencies. Learn more about Socket for GitHub. |
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
// wallet_notify for solana accountChanged when permission changes | ||
controllerMessenger.subscribe( | ||
`${this.permissionController.name}:stateChange`, | ||
async (currentValue, previousValue) => { | ||
const origins = uniq([ | ||
...previousValue.keys(), | ||
...currentValue.keys(), | ||
]); | ||
origins.forEach((origin) => { | ||
const previousCaveatValue = previousValue.get(origin); | ||
const currentCaveatValue = currentValue.get(origin); | ||
|
||
const previousSolanaAccountChangedNotificationsEnabled = Boolean( | ||
previousCaveatValue?.sessionProperties?.[ | ||
KnownSessionProperties.SolanaAccountChangedNotifications | ||
], | ||
); | ||
const currentSolanaAccountChangedNotificationsEnabled = Boolean( | ||
currentCaveatValue?.sessionProperties?.[ | ||
KnownSessionProperties.SolanaAccountChangedNotifications | ||
], | ||
); | ||
|
||
if ( | ||
!previousSolanaAccountChangedNotificationsEnabled && | ||
!currentSolanaAccountChangedNotificationsEnabled | ||
) { | ||
return; | ||
} | ||
|
||
const previousSolanaCaipAccountIds = previousCaveatValue | ||
? getPermittedAccountsForScopes(previousCaveatValue, [ | ||
MultichainNetworks.SOLANA, | ||
MultichainNetworks.SOLANA_DEVNET, | ||
MultichainNetworks.SOLANA_TESTNET, | ||
]) | ||
: []; | ||
const previousNonUniqueSolanaHexAccountAddresses = | ||
previousSolanaCaipAccountIds.map((caipAccountId) => { | ||
const { address } = parseCaipAccountId(caipAccountId); | ||
return address; | ||
}); | ||
const previousSolanaHexAccountAddresses = uniq( | ||
previousNonUniqueSolanaHexAccountAddresses, | ||
); | ||
const [previousSelectedSolanaAccountAddress] = | ||
this.sortMultichainAccountsByLastSelected( | ||
previousSolanaHexAccountAddresses, | ||
); | ||
|
||
const currentSolanaCaipAccountIds = currentCaveatValue | ||
? getPermittedAccountsForScopes(currentCaveatValue, [ | ||
MultichainNetworks.SOLANA, | ||
MultichainNetworks.SOLANA_DEVNET, | ||
MultichainNetworks.SOLANA_TESTNET, | ||
]) | ||
: []; | ||
const currentNonUniqueSolanaHexAccountAddresses = | ||
currentSolanaCaipAccountIds.map((caipAccountId) => { | ||
const { address } = parseCaipAccountId(caipAccountId); | ||
return address; | ||
}); | ||
const currentSolanaHexAccountAddresses = uniq( | ||
currentNonUniqueSolanaHexAccountAddresses, | ||
); | ||
const [currentSelectedSolanaAccountAddress] = | ||
this.sortMultichainAccountsByLastSelected( | ||
currentSolanaHexAccountAddresses, | ||
); | ||
|
||
if ( | ||
previousSelectedSolanaAccountAddress !== | ||
currentSelectedSolanaAccountAddress | ||
) { | ||
// TODO: [ffmcgee] implement notifySolanaAccountChange ? | ||
// this._notifySolanaAccountChange( | ||
// origin, | ||
// currentSelectedSolanaAccountAddress | ||
// ? [currentSelectedSolanaAccountAddress] | ||
// : [], | ||
// ); | ||
} | ||
}); | ||
}, | ||
getAuthorizedScopesByOrigin, | ||
); | ||
|
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.
// wallet_notify for solana accountChanged when permission changes | |
controllerMessenger.subscribe( | |
`${this.permissionController.name}:stateChange`, | |
async (currentValue, previousValue) => { | |
const origins = uniq([ | |
...previousValue.keys(), | |
...currentValue.keys(), | |
]); | |
origins.forEach((origin) => { | |
const previousCaveatValue = previousValue.get(origin); | |
const currentCaveatValue = currentValue.get(origin); | |
const previousSolanaAccountChangedNotificationsEnabled = Boolean( | |
previousCaveatValue?.sessionProperties?.[ | |
KnownSessionProperties.SolanaAccountChangedNotifications | |
], | |
); | |
const currentSolanaAccountChangedNotificationsEnabled = Boolean( | |
currentCaveatValue?.sessionProperties?.[ | |
KnownSessionProperties.SolanaAccountChangedNotifications | |
], | |
); | |
if ( | |
!previousSolanaAccountChangedNotificationsEnabled && | |
!currentSolanaAccountChangedNotificationsEnabled | |
) { | |
return; | |
} | |
const previousSolanaCaipAccountIds = previousCaveatValue | |
? getPermittedAccountsForScopes(previousCaveatValue, [ | |
MultichainNetworks.SOLANA, | |
MultichainNetworks.SOLANA_DEVNET, | |
MultichainNetworks.SOLANA_TESTNET, | |
]) | |
: []; | |
const previousNonUniqueSolanaHexAccountAddresses = | |
previousSolanaCaipAccountIds.map((caipAccountId) => { | |
const { address } = parseCaipAccountId(caipAccountId); | |
return address; | |
}); | |
const previousSolanaHexAccountAddresses = uniq( | |
previousNonUniqueSolanaHexAccountAddresses, | |
); | |
const [previousSelectedSolanaAccountAddress] = | |
this.sortMultichainAccountsByLastSelected( | |
previousSolanaHexAccountAddresses, | |
); | |
const currentSolanaCaipAccountIds = currentCaveatValue | |
? getPermittedAccountsForScopes(currentCaveatValue, [ | |
MultichainNetworks.SOLANA, | |
MultichainNetworks.SOLANA_DEVNET, | |
MultichainNetworks.SOLANA_TESTNET, | |
]) | |
: []; | |
const currentNonUniqueSolanaHexAccountAddresses = | |
currentSolanaCaipAccountIds.map((caipAccountId) => { | |
const { address } = parseCaipAccountId(caipAccountId); | |
return address; | |
}); | |
const currentSolanaHexAccountAddresses = uniq( | |
currentNonUniqueSolanaHexAccountAddresses, | |
); | |
const [currentSelectedSolanaAccountAddress] = | |
this.sortMultichainAccountsByLastSelected( | |
currentSolanaHexAccountAddresses, | |
); | |
if ( | |
previousSelectedSolanaAccountAddress !== | |
currentSelectedSolanaAccountAddress | |
) { | |
// TODO: [ffmcgee] implement notifySolanaAccountChange ? | |
// this._notifySolanaAccountChange( | |
// origin, | |
// currentSelectedSolanaAccountAddress | |
// ? [currentSelectedSolanaAccountAddress] | |
// : [], | |
// ); | |
} | |
}); | |
}, | |
getAuthorizedScopesByOrigin, | |
); |
This should be added in a separate PR later on, per our sequencing/breakdown: https://docs.google.com/document/d/1uUK2L6KBSHnz5yzyW54MVYhsSXcaZajNKVIUczljL8g/edit?tab=t.0
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.
* Note that account-related notifications emitted when the extension | ||
* becomes unlocked are handled in MetaMaskController._onUnlock. | ||
*/ | ||
setupControllerEventSubscriptions() { |
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.
Have we verified whether some of these subscriptions are being handled elsewhere?
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 smartTransactionPoller
logic seems to be handled in the Engine
https://github.com/MetaMask/metamask-mobile/blob/main/app/core/Engine/Engine.ts#L1507C10-L1507C22, but the starting condition doesn't seem to be the same.
and _checkTokenListPolling
doesn't seem to be handled elsewhere.
so all in all, if we are talking about controllerMessenger subscription to PreferencesController:stateChange
, none existed prior to this implementation.
if (chains.length > 0 && !chains.includes(currentChainIdForOrigin)) { | ||
const networkClientId = | ||
NetworkController.findNetworkClientIdByChainId(chains[0]); | ||
// setActiveNetwork should be called before setNetworkClientIdForDomain | ||
// to ensure that the isConnected value can be accurately inferred from | ||
// NetworkController.state.networksMetadata in return value of | ||
// `metamask_getProviderState` requests and `metamask_chainChanged` events. | ||
NetworkController.setActiveNetwork(networkClientId); | ||
SelectedNetworkController.setNetworkClientIdForDomain( | ||
origin, | ||
networkClientId, | ||
); | ||
} |
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'll need to verify whether this is in place somewhere for the WIP per-dapp selected network feature still being finished on Mobile by Eric Lamontagne (don't remember his gh handle)
controllerMessenger.subscribe( | ||
'NetworkController:networkDidChange', | ||
async () => { | ||
if (PreferencesController.state.useExternalServices) { | ||
TransactionController.stopIncomingTransactionPolling(); | ||
await TransactionController.updateIncomingTransactions(); | ||
TransactionController.startIncomingTransactionPolling(); | ||
} | ||
}, |
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 imagine this must exist somewhere else already...
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.
searching up NetworkController:networkDidChange
, it doesn't seem to be the case.
I only see stuff such as this, and not an actual subscription by the controllerMessenger
to this action.
|
|
…d testability - Added comprehensive tests for utility functions in TASK_QUALITY_TEST.md, improving coverage metrics significantly. - Refactored BackgroundBridge.js to convert private methods to regular methods, enhancing testability and adding safety checks. - Updated BackgroundBridge.test.js with new tests for transaction polling and token list management. - Improved permission differencing utilities tests in differs.test.ts for better coverage and clarity. - Enhanced validator utilities tests in index.test.ts to cover edge cases and improve validation logic.
4e8b903
to
ae96745
Compare
Description
This branch adds support for the Multichain API to the Flask build of the Extension.
The existing API (via injected provider) should be completely unchanged.
(Very Briefly) What is the MetaMask Multichain API
window.postMessage()
. Not accessible via an injected global likewindow.ethereum
Key Documents/Standards
mip = MetaMask Improvement Proposal
Manual testing steps
(RECOMMENDED) Use the Multichain Test Dapp
NOTE:
window.postMessage
should be used as extensionId for mobile.OR
Then
or
Setup event listener via dev tools
Send a multichain API request via dev tools
More detailed example of manual requests
taken from extension equivalent Add Multichain API to Flask work
Pre-merge author checklist
Pre-merge reviewer checklist