@metamask/multichain-account-service
Version:
Service to manage multichain accounts
245 lines • 14.6 kB
JavaScript
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _MultichainAccountService_instances, _MultichainAccountService_messenger, _MultichainAccountService_providers, _MultichainAccountService_wallets, _MultichainAccountService_accountIdToContext, _MultichainAccountService_handleOnAccountAdded, _MultichainAccountService_handleOnAccountRemoved, _MultichainAccountService_getWallet;
import { isBip44Account, toMultichainAccountWalletId } from "@metamask/account-api";
import { KeyringTypes } from "@metamask/keyring-controller";
import { MultichainAccountWallet } from "./MultichainAccountWallet.mjs";
import { EvmAccountProvider } from "./providers/EvmAccountProvider.mjs";
import { SolAccountProvider } from "./providers/SolAccountProvider.mjs";
export const serviceName = 'MultichainAccountService';
/**
* Service to expose multichain accounts capabilities.
*/
export class MultichainAccountService {
/**
* Constructs a new MultichainAccountService.
*
* @param options - The options.
* @param options.messenger - The messenger suited to this
* MultichainAccountService.
* @param options.providers - Optional list of account
* providers.
*/
constructor({ messenger, providers = [], }) {
_MultichainAccountService_instances.add(this);
_MultichainAccountService_messenger.set(this, void 0);
_MultichainAccountService_providers.set(this, void 0);
_MultichainAccountService_wallets.set(this, void 0);
_MultichainAccountService_accountIdToContext.set(this, void 0);
/**
* The name of the service.
*/
this.name = serviceName;
__classPrivateFieldSet(this, _MultichainAccountService_messenger, messenger, "f");
__classPrivateFieldSet(this, _MultichainAccountService_wallets, new Map(), "f");
__classPrivateFieldSet(this, _MultichainAccountService_accountIdToContext, new Map(), "f");
// TODO: Rely on keyring capabilities once the keyring API is used by all keyrings.
__classPrivateFieldSet(this, _MultichainAccountService_providers, [
new EvmAccountProvider(__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f")),
new SolAccountProvider(__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f")),
// Custom account providers that can be provided by the MetaMask client.
...providers,
], "f");
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:getMultichainAccountGroup', (...args) => this.getMultichainAccountGroup(...args));
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:getMultichainAccountGroups', (...args) => this.getMultichainAccountGroups(...args));
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:getMultichainAccountWallet', (...args) => this.getMultichainAccountWallet(...args));
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:getMultichainAccountWallets', (...args) => this.getMultichainAccountWallets(...args));
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:createNextMultichainAccountGroup', (...args) => this.createNextMultichainAccountGroup(...args));
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:createMultichainAccountGroup', (...args) => this.createMultichainAccountGroup(...args));
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:alignWallets', (...args) => this.alignWallets(...args));
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").registerActionHandler('MultichainAccountService:alignWallet', (...args) => this.alignWallet(...args));
}
/**
* Initialize the service and constructs the internal reprensentation of
* multichain accounts and wallets.
*/
init() {
// Create initial wallets.
const { keyrings } = __classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").call('KeyringController:getState');
for (const keyring of keyrings) {
if (keyring.type === KeyringTypes.hd) {
// Only HD keyrings have an entropy source/SRP.
const entropySource = keyring.metadata.id;
// This will automatically "associate" all multichain accounts for that wallet
// (based on the accounts owned by each account providers).
const wallet = new MultichainAccountWallet({
entropySource,
providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
});
__classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
// Reverse mapping between account ID and their multichain wallet/account:
for (const group of wallet.getMultichainAccountGroups()) {
for (const account of group.getAccounts()) {
__classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").set(account.id, {
wallet,
group,
});
}
}
}
}
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").subscribe('AccountsController:accountAdded', (account) => __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_handleOnAccountAdded).call(this, account));
__classPrivateFieldGet(this, _MultichainAccountService_messenger, "f").subscribe('AccountsController:accountRemoved', (id) => __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_handleOnAccountRemoved).call(this, id));
}
/**
* Gets the account's context which contains its multichain wallet and
* multichain account group references.
*
* @param id - Account ID.
* @returns The account context if any, undefined otherwise.
*/
getAccountContext(id) {
return __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").get(id);
}
/**
* Gets a reference to the multichain account wallet matching this entropy source.
*
* @param options - Options.
* @param options.entropySource - The entropy source of the multichain account.
* @throws If none multichain account match this entropy.
* @returns A reference to the multichain account wallet.
*/
getMultichainAccountWallet({ entropySource, }) {
return __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getWallet).call(this, entropySource);
}
/**
* Gets an array of all multichain account wallets.
*
* @returns An array of all multichain account wallets.
*/
getMultichainAccountWallets() {
return Array.from(__classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").values());
}
/**
* Gets a reference to the multichain account group matching this entropy source
* and a group index.
*
* @param options - Options.
* @param options.entropySource - The entropy source of the multichain account.
* @param options.groupIndex - The group index of the multichain account.
* @throws If none multichain account match this entropy source and group index.
* @returns A reference to the multichain account.
*/
getMultichainAccountGroup({ entropySource, groupIndex, }) {
const multichainAccount = __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getWallet).call(this, entropySource).getMultichainAccountGroup(groupIndex);
if (!multichainAccount) {
throw new Error(`No multichain account for index: ${groupIndex}`);
}
return multichainAccount;
}
/**
* Gets all multichain account groups for a given entropy source.
*
* @param options - Options.
* @param options.entropySource - The entropy source to query.
* @throws If no multichain accounts match this entropy source.
* @returns A list of all multichain accounts.
*/
getMultichainAccountGroups({ entropySource, }) {
return __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getWallet).call(this, entropySource).getMultichainAccountGroups();
}
/**
* Creates the next multichain account group.
*
* @param options - Options.
* @param options.entropySource - The wallet's entropy source.
* @returns The next multichain account group.
*/
async createNextMultichainAccountGroup({ entropySource, }) {
return await __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getWallet).call(this, entropySource).createNextMultichainAccountGroup();
}
/**
* Creates a multichain account group.
*
* @param options - Options.
* @param options.groupIndex - The group index to use.
* @param options.entropySource - The wallet's entropy source.
* @returns The multichain account group for this group index.
*/
async createMultichainAccountGroup({ groupIndex, entropySource, }) {
return await __classPrivateFieldGet(this, _MultichainAccountService_instances, "m", _MultichainAccountService_getWallet).call(this, entropySource).createMultichainAccountGroup(groupIndex);
}
/**
* Align all multichain account wallets.
*/
async alignWallets() {
const wallets = this.getMultichainAccountWallets();
await Promise.all(wallets.map((w) => w.alignGroups()));
}
/**
* Align a specific multichain account wallet.
*
* @param entropySource - The entropy source of the multichain account wallet.
*/
async alignWallet(entropySource) {
const wallet = this.getMultichainAccountWallet({ entropySource });
await wallet.alignGroups();
}
}
_MultichainAccountService_messenger = new WeakMap(), _MultichainAccountService_providers = new WeakMap(), _MultichainAccountService_wallets = new WeakMap(), _MultichainAccountService_accountIdToContext = new WeakMap(), _MultichainAccountService_instances = new WeakSet(), _MultichainAccountService_handleOnAccountAdded = function _MultichainAccountService_handleOnAccountAdded(account) {
// We completely omit non-BIP-44 accounts!
if (!isBip44Account(account)) {
return;
}
let sync = true;
let wallet = __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").get(toMultichainAccountWalletId(account.options.entropy.id));
if (!wallet) {
// That's a new wallet.
wallet = new MultichainAccountWallet({
entropySource: account.options.entropy.id,
providers: __classPrivateFieldGet(this, _MultichainAccountService_providers, "f"),
});
__classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").set(wallet.id, wallet);
// If that's a new wallet wallet. There's nothing to "force-sync".
sync = false;
}
let group = wallet.getMultichainAccountGroup(account.options.entropy.groupIndex);
if (!group) {
// This new account is a new multichain account, let the wallet know
// it has to re-sync with its providers.
if (sync) {
wallet.sync();
}
group = wallet.getMultichainAccountGroup(account.options.entropy.groupIndex);
// If that's a new multichain account. There's nothing to "force-sync".
sync = false;
}
// We have to check against `undefined` in case `getMultichainAccount` is
// not able to find this multichain account (which should not be possible...)
if (group) {
if (sync) {
group.sync();
}
// Same here, this account should have been already grouped in that
// multichain account.
__classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").set(account.id, {
wallet,
group,
});
}
}, _MultichainAccountService_handleOnAccountRemoved = function _MultichainAccountService_handleOnAccountRemoved(id) {
// Force sync of the appropriate wallet if an account got removed.
const found = __classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").get(id);
if (found) {
const { wallet } = found;
wallet.sync();
}
// Safe to call delete even if the `id` was not referencing a BIP-44 account.
__classPrivateFieldGet(this, _MultichainAccountService_accountIdToContext, "f").delete(id);
}, _MultichainAccountService_getWallet = function _MultichainAccountService_getWallet(entropySource) {
const wallet = __classPrivateFieldGet(this, _MultichainAccountService_wallets, "f").get(toMultichainAccountWalletId(entropySource));
if (!wallet) {
throw new Error('Unknown wallet, no wallet matching this entropy source');
}
return wallet;
};
//# sourceMappingURL=MultichainAccountService.mjs.map