@metamask-previews/multichain-account-service 4.1.0-preview-a9886279 → 5.0.0-preview-6a568504
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -1
- package/dist/MultichainAccountGroup.cjs +84 -45
- package/dist/MultichainAccountGroup.cjs.map +1 -1
- package/dist/MultichainAccountGroup.d.cts +17 -4
- package/dist/MultichainAccountGroup.d.cts.map +1 -1
- package/dist/MultichainAccountGroup.d.mts +17 -4
- package/dist/MultichainAccountGroup.d.mts.map +1 -1
- package/dist/MultichainAccountGroup.mjs +84 -45
- package/dist/MultichainAccountGroup.mjs.map +1 -1
- package/dist/MultichainAccountService.cjs +150 -112
- package/dist/MultichainAccountService.cjs.map +1 -1
- package/dist/MultichainAccountService.d.cts +49 -20
- package/dist/MultichainAccountService.d.cts.map +1 -1
- package/dist/MultichainAccountService.d.mts +49 -20
- package/dist/MultichainAccountService.d.mts.map +1 -1
- package/dist/MultichainAccountService.mjs +151 -113
- package/dist/MultichainAccountService.mjs.map +1 -1
- package/dist/MultichainAccountWallet.cjs +108 -123
- package/dist/MultichainAccountWallet.cjs.map +1 -1
- package/dist/MultichainAccountWallet.d.cts +5 -4
- package/dist/MultichainAccountWallet.d.cts.map +1 -1
- package/dist/MultichainAccountWallet.d.mts +5 -4
- package/dist/MultichainAccountWallet.d.mts.map +1 -1
- package/dist/MultichainAccountWallet.mjs +108 -123
- package/dist/MultichainAccountWallet.mjs.map +1 -1
- package/dist/providers/AccountProviderWrapper.cjs +18 -0
- package/dist/providers/AccountProviderWrapper.cjs.map +1 -1
- package/dist/providers/AccountProviderWrapper.d.cts +12 -0
- package/dist/providers/AccountProviderWrapper.d.cts.map +1 -1
- package/dist/providers/AccountProviderWrapper.d.mts +12 -0
- package/dist/providers/AccountProviderWrapper.d.mts.map +1 -1
- package/dist/providers/AccountProviderWrapper.mjs +18 -0
- package/dist/providers/AccountProviderWrapper.mjs.map +1 -1
- package/dist/providers/BaseBip44AccountProvider.cjs +45 -20
- package/dist/providers/BaseBip44AccountProvider.cjs.map +1 -1
- package/dist/providers/BaseBip44AccountProvider.d.cts +58 -6
- package/dist/providers/BaseBip44AccountProvider.d.cts.map +1 -1
- package/dist/providers/BaseBip44AccountProvider.d.mts +58 -6
- package/dist/providers/BaseBip44AccountProvider.d.mts.map +1 -1
- package/dist/providers/BaseBip44AccountProvider.mjs +45 -20
- package/dist/providers/BaseBip44AccountProvider.mjs.map +1 -1
- package/dist/providers/BtcAccountProvider.cjs +47 -32
- package/dist/providers/BtcAccountProvider.cjs.map +1 -1
- package/dist/providers/BtcAccountProvider.d.cts +2 -1
- package/dist/providers/BtcAccountProvider.d.cts.map +1 -1
- package/dist/providers/BtcAccountProvider.d.mts +2 -1
- package/dist/providers/BtcAccountProvider.d.mts.map +1 -1
- package/dist/providers/BtcAccountProvider.mjs +47 -32
- package/dist/providers/BtcAccountProvider.mjs.map +1 -1
- package/dist/providers/EvmAccountProvider.cjs +39 -5
- package/dist/providers/EvmAccountProvider.cjs.map +1 -1
- package/dist/providers/EvmAccountProvider.d.cts +8 -0
- package/dist/providers/EvmAccountProvider.d.cts.map +1 -1
- package/dist/providers/EvmAccountProvider.d.mts +8 -0
- package/dist/providers/EvmAccountProvider.d.mts.map +1 -1
- package/dist/providers/EvmAccountProvider.mjs +39 -5
- package/dist/providers/EvmAccountProvider.mjs.map +1 -1
- package/dist/providers/SnapAccountProvider.cjs +81 -54
- package/dist/providers/SnapAccountProvider.cjs.map +1 -1
- package/dist/providers/SnapAccountProvider.d.cts +16 -4
- package/dist/providers/SnapAccountProvider.d.cts.map +1 -1
- package/dist/providers/SnapAccountProvider.d.mts +16 -4
- package/dist/providers/SnapAccountProvider.d.mts.map +1 -1
- package/dist/providers/SnapAccountProvider.mjs +81 -54
- package/dist/providers/SnapAccountProvider.mjs.map +1 -1
- package/dist/providers/SolAccountProvider.cjs +40 -31
- package/dist/providers/SolAccountProvider.cjs.map +1 -1
- package/dist/providers/SolAccountProvider.d.cts.map +1 -1
- package/dist/providers/SolAccountProvider.d.mts.map +1 -1
- package/dist/providers/SolAccountProvider.mjs +40 -31
- package/dist/providers/SolAccountProvider.mjs.map +1 -1
- package/dist/providers/TrxAccountProvider.cjs +48 -29
- package/dist/providers/TrxAccountProvider.cjs.map +1 -1
- package/dist/providers/TrxAccountProvider.d.cts +1 -0
- package/dist/providers/TrxAccountProvider.d.cts.map +1 -1
- package/dist/providers/TrxAccountProvider.d.mts +1 -0
- package/dist/providers/TrxAccountProvider.d.mts.map +1 -1
- package/dist/providers/TrxAccountProvider.mjs +48 -29
- package/dist/providers/TrxAccountProvider.mjs.map +1 -1
- package/dist/snaps/SnapPlatformWatcher.cjs +60 -0
- package/dist/snaps/SnapPlatformWatcher.cjs.map +1 -0
- package/dist/snaps/SnapPlatformWatcher.d.cts +8 -0
- package/dist/snaps/SnapPlatformWatcher.d.cts.map +1 -0
- package/dist/snaps/SnapPlatformWatcher.d.mts +8 -0
- package/dist/snaps/SnapPlatformWatcher.d.mts.map +1 -0
- package/dist/snaps/SnapPlatformWatcher.mjs +57 -0
- package/dist/snaps/SnapPlatformWatcher.mjs.map +1 -0
- package/dist/tests/messenger.cjs +12 -1
- package/dist/tests/messenger.cjs.map +1 -1
- package/dist/tests/messenger.d.cts +9 -4
- package/dist/tests/messenger.d.cts.map +1 -1
- package/dist/tests/messenger.d.mts +9 -4
- package/dist/tests/messenger.d.mts.map +1 -1
- package/dist/tests/messenger.mjs +12 -1
- package/dist/tests/messenger.mjs.map +1 -1
- package/dist/tests/providers.cjs +62 -7
- package/dist/tests/providers.cjs.map +1 -1
- package/dist/tests/providers.d.cts +17 -3
- package/dist/tests/providers.d.cts.map +1 -1
- package/dist/tests/providers.d.mts +17 -3
- package/dist/tests/providers.d.mts.map +1 -1
- package/dist/tests/providers.mjs +60 -6
- package/dist/tests/providers.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +14 -6
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +14 -6
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/utils.cjs +1 -11
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +0 -1
- package/dist/utils.d.cts.map +1 -1
- package/dist/utils.d.mts +0 -1
- package/dist/utils.d.mts.map +1 -1
- package/dist/utils.mjs +0 -9
- package/dist/utils.mjs.map +1 -1
- package/package.json +3 -2
|
@@ -9,8 +9,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
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");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _EvmAccountProvider_instances, _EvmAccountProvider_config, _EvmAccountProvider_trace, _EvmAccountProvider_createAccount, _EvmAccountProvider_getTransactionCount, _EvmAccountProvider_getAddressFromGroupIndex;
|
|
12
|
+
var _EvmAccountProvider_instances, _EvmAccountProvider_config, _EvmAccountProvider_trace, _EvmAccountProvider_getAccountId, _EvmAccountProvider_createAccount, _EvmAccountProvider_getTransactionCount, _EvmAccountProvider_getAddressFromGroupIndex;
|
|
13
13
|
import { publicToAddress } from "@ethereumjs/util";
|
|
14
|
+
import { getUUIDFromAddressOfNormalAccount } from "@metamask/accounts-controller";
|
|
14
15
|
import { EthAccountType } from "@metamask/keyring-api";
|
|
15
16
|
import { KeyringTypes } from "@metamask/keyring-controller";
|
|
16
17
|
import { add0x, assert, bytesToHex, isStrictHexString } from "@metamask/utils";
|
|
@@ -71,17 +72,27 @@ export class EvmAccountProvider extends BaseBip44AccountProvider {
|
|
|
71
72
|
const { provider } = this.messenger.call('NetworkController:getNetworkClientById', networkClientId);
|
|
72
73
|
return provider;
|
|
73
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Create accounts for the EVM provider.
|
|
77
|
+
*
|
|
78
|
+
* @param opts - The options for the creation of the accounts.
|
|
79
|
+
* @param opts.entropySource - The entropy source to use for the creation of the accounts.
|
|
80
|
+
* @param opts.groupIndex - The index of the group to create the accounts for.
|
|
81
|
+
* @returns The accounts for the EVM provider.
|
|
82
|
+
*/
|
|
74
83
|
async createAccounts({ entropySource, groupIndex, }) {
|
|
75
84
|
const [address] = await __classPrivateFieldGet(this, _EvmAccountProvider_instances, "m", _EvmAccountProvider_createAccount).call(this, {
|
|
76
85
|
entropySource,
|
|
77
86
|
groupIndex,
|
|
78
87
|
throwOnGap: true,
|
|
79
88
|
});
|
|
80
|
-
const
|
|
89
|
+
const accountId = __classPrivateFieldGet(this, _EvmAccountProvider_instances, "m", _EvmAccountProvider_getAccountId).call(this, address);
|
|
90
|
+
const account = this.messenger.call('AccountsController:getAccount', accountId);
|
|
81
91
|
// We MUST have the associated internal account.
|
|
82
92
|
assertInternalAccountExists(account);
|
|
83
93
|
const accountsArray = [account];
|
|
84
94
|
assertAreBip44Accounts(accountsArray);
|
|
95
|
+
this.accounts.add(account.id);
|
|
85
96
|
return accountsArray;
|
|
86
97
|
}
|
|
87
98
|
/**
|
|
@@ -118,9 +129,11 @@ export class EvmAccountProvider extends BaseBip44AccountProvider {
|
|
|
118
129
|
groupIndex,
|
|
119
130
|
});
|
|
120
131
|
assert(addressFromGroupIndex === address, 'Created account does not match address from group index.');
|
|
121
|
-
const
|
|
132
|
+
const accoundId = __classPrivateFieldGet(this, _EvmAccountProvider_instances, "m", _EvmAccountProvider_getAccountId).call(this, address);
|
|
133
|
+
const account = this.messenger.call('AccountsController:getAccount', accoundId);
|
|
122
134
|
assertInternalAccountExists(account);
|
|
123
135
|
assertIsBip44Account(account);
|
|
136
|
+
this.accounts.add(account.id);
|
|
124
137
|
return [account];
|
|
125
138
|
});
|
|
126
139
|
}
|
|
@@ -129,7 +142,19 @@ export class EvmAccountProvider extends BaseBip44AccountProvider {
|
|
|
129
142
|
// the MetaMask side.
|
|
130
143
|
}
|
|
131
144
|
}
|
|
132
|
-
_EvmAccountProvider_config = new WeakMap(), _EvmAccountProvider_trace = new WeakMap(), _EvmAccountProvider_instances = new WeakSet(),
|
|
145
|
+
_EvmAccountProvider_config = new WeakMap(), _EvmAccountProvider_trace = new WeakMap(), _EvmAccountProvider_instances = new WeakSet(), _EvmAccountProvider_getAccountId = function _EvmAccountProvider_getAccountId(address) {
|
|
146
|
+
return getUUIDFromAddressOfNormalAccount(address);
|
|
147
|
+
}, _EvmAccountProvider_createAccount =
|
|
148
|
+
/**
|
|
149
|
+
* Create an EVM account.
|
|
150
|
+
*
|
|
151
|
+
* @param opts - The options for the creation of the account.
|
|
152
|
+
* @param opts.entropySource - The entropy source to use for the creation of the account.
|
|
153
|
+
* @param opts.groupIndex - The index of the group to create the account for.
|
|
154
|
+
* @param opts.throwOnGap - Whether to throw an error if the account index is not contiguous.
|
|
155
|
+
* @returns The account ID and a boolean indicating if the account was created.
|
|
156
|
+
*/
|
|
157
|
+
async function _EvmAccountProvider_createAccount({ entropySource, groupIndex, throwOnGap = false, }) {
|
|
133
158
|
const result = await this.withKeyring({ id: entropySource }, async ({ keyring }) => {
|
|
134
159
|
const existing = await keyring.getAccounts();
|
|
135
160
|
if (groupIndex < existing.length) {
|
|
@@ -143,7 +168,16 @@ _EvmAccountProvider_config = new WeakMap(), _EvmAccountProvider_trace = new Weak
|
|
|
143
168
|
return [added, true];
|
|
144
169
|
});
|
|
145
170
|
return result;
|
|
146
|
-
}, _EvmAccountProvider_getTransactionCount =
|
|
171
|
+
}, _EvmAccountProvider_getTransactionCount =
|
|
172
|
+
/**
|
|
173
|
+
* Get the transaction count for an EVM account.
|
|
174
|
+
* This method uses a retry and timeout mechanism to handle transient failures.
|
|
175
|
+
*
|
|
176
|
+
* @param provider - The provider to use for the transaction count.
|
|
177
|
+
* @param address - The address of the account.
|
|
178
|
+
* @returns The transaction count.
|
|
179
|
+
*/
|
|
180
|
+
async function _EvmAccountProvider_getTransactionCount(provider, address) {
|
|
147
181
|
const method = 'eth_getTransactionCount';
|
|
148
182
|
const response = await withRetry(() => withTimeout(provider.request({
|
|
149
183
|
method,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EvmAccountProvider.mjs","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { publicToAddress } from '@ethereumjs/util';\nimport type { Bip44Account } from '@metamask/account-api';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { HdKeyring } from '@metamask/eth-hd-keyring';\nimport type { EntropySourceId, KeyringAccount } from '@metamask/keyring-api';\nimport { EthAccountType } from '@metamask/keyring-api';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type {\n EthKeyring,\n InternalAccount,\n} from '@metamask/keyring-internal-api';\nimport type { Provider } from '@metamask/network-controller';\nimport { add0x, assert, bytesToHex, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport {\n assertAreBip44Accounts,\n assertIsBip44Account,\n BaseBip44AccountProvider,\n} from './BaseBip44AccountProvider';\nimport { withRetry, withTimeout } from './utils';\nimport { traceFallback } from '../analytics';\nimport { TraceName } from '../constants/traces';\nimport { projectLogger as log, WARNING_PREFIX } from '../logger';\nimport type { MultichainAccountServiceMessenger } from '../types';\n\nconst ETH_MAINNET_CHAIN_ID = '0x1';\n\n/**\n * Asserts an internal account exists.\n *\n * @param account - The internal account to check.\n * @throws An error if the internal account does not exist.\n */\nfunction assertInternalAccountExists(\n account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n if (!account) {\n throw new Error('Internal account does not exist');\n }\n}\n\nexport type EvmAccountProviderConfig = {\n discovery: {\n enabled?: boolean;\n maxAttempts: number;\n timeoutMs: number;\n backOffMs: number;\n };\n};\n\nexport const EVM_ACCOUNT_PROVIDER_NAME = 'EVM';\n\nexport const EVM_ACCOUNT_PROVIDER_DEFAULT_CONFIG = {\n discovery: {\n maxAttempts: 3,\n timeoutMs: 500,\n backOffMs: 500,\n },\n};\n\nexport class EvmAccountProvider extends BaseBip44AccountProvider {\n static NAME = EVM_ACCOUNT_PROVIDER_NAME;\n\n readonly #config: EvmAccountProviderConfig;\n\n readonly #trace: TraceCallback;\n\n constructor(\n messenger: MultichainAccountServiceMessenger,\n config: EvmAccountProviderConfig = EVM_ACCOUNT_PROVIDER_DEFAULT_CONFIG,\n trace?: TraceCallback,\n ) {\n super(messenger);\n this.#config = {\n ...config,\n discovery: {\n ...config.discovery,\n enabled: config.discovery.enabled ?? true,\n },\n };\n this.#trace = trace ?? traceFallback;\n }\n\n isAccountCompatible(account: Bip44Account<InternalAccount>): boolean {\n return (\n account.type === EthAccountType.Eoa &&\n account.metadata.keyring.type === (KeyringTypes.hd as string)\n );\n }\n\n getName(): string {\n return EvmAccountProvider.NAME;\n }\n\n /**\n * Get the EVM provider.\n *\n * @returns The EVM provider.\n */\n getEvmProvider(): Provider {\n const networkClientId = this.messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n ETH_MAINNET_CHAIN_ID,\n );\n const { provider } = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n return provider;\n }\n\n async #createAccount({\n entropySource,\n groupIndex,\n throwOnGap = false,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n throwOnGap?: boolean;\n }): Promise<[Hex, boolean]> {\n const result = await this.withKeyring<EthKeyring, [Hex, boolean]>(\n { id: entropySource },\n async ({ keyring }) => {\n const existing = await keyring.getAccounts();\n if (groupIndex < existing.length) {\n return [existing[groupIndex], false];\n }\n\n // If the throwOnGap flag is set, we throw an error to prevent index gaps.\n if (throwOnGap && groupIndex !== existing.length) {\n throw new Error('Trying to create too many accounts');\n }\n\n const [added] = await keyring.addAccounts(1);\n return [added, true];\n },\n );\n\n return result;\n }\n\n async createAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]> {\n const [address] = await this.#createAccount({\n entropySource,\n groupIndex,\n throwOnGap: true,\n });\n\n const account = this.messenger.call(\n 'AccountsController:getAccountByAddress',\n address,\n );\n\n // We MUST have the associated internal account.\n assertInternalAccountExists(account);\n\n const accountsArray = [account];\n assertAreBip44Accounts(accountsArray);\n\n return accountsArray;\n }\n\n async #getTransactionCount(\n provider: Provider,\n address: Hex,\n ): Promise<number> {\n const method = 'eth_getTransactionCount';\n\n const response = await withRetry(\n () =>\n withTimeout(\n provider.request({\n method,\n params: [address, 'latest'],\n }),\n this.#config.discovery.timeoutMs,\n ),\n {\n maxAttempts: this.#config.discovery.maxAttempts,\n backOffMs: this.#config.discovery.backOffMs,\n },\n );\n\n // Make sure we got the right response format, if not, we fallback to \"0x0\", to avoid having to deal with `NaN`.\n if (!isStrictHexString(response)) {\n const message = `Received invalid hex response from \"${method}\" request: ${JSON.stringify(response)}`;\n\n log(`${WARNING_PREFIX} ${message}`);\n console.warn(message);\n\n return 0;\n }\n\n return parseInt(response, 16);\n }\n\n async #getAddressFromGroupIndex({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Hex> {\n // NOTE: To avoid exposing this function at keyring level, we just re-use its internal state\n // and compute the derivation here.\n return await this.withKeyring<HdKeyring, Hex>(\n { id: entropySource },\n async ({ keyring }) => {\n // If the account already exist, do not re-derive and just re-use that account.\n const existing = await keyring.getAccounts();\n if (groupIndex < existing.length) {\n return existing[groupIndex];\n }\n\n // If not, then we just \"peek\" the next address to avoid creating the account.\n assert(keyring.root, 'Expected HD keyring.root to be set');\n const hdKey = keyring.root.deriveChild(groupIndex);\n assert(hdKey.publicKey, 'Expected public key to be set');\n\n return add0x(\n bytesToHex(publicToAddress(hdKey.publicKey, true)).toLowerCase(),\n );\n },\n );\n }\n\n /**\n * Discover and create accounts for the EVM provider.\n *\n * @param opts - The options for the discovery and creation of accounts.\n * @param opts.entropySource - The entropy source to use for the discovery and creation of accounts.\n * @param opts.groupIndex - The index of the group to create the accounts for.\n * @returns The accounts for the EVM provider.\n */\n async discoverAccounts(opts: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]> {\n return this.#trace(\n {\n name: TraceName.EvmDiscoverAccounts,\n data: {\n provider: this.getName(),\n },\n },\n async () => {\n if (!this.#config.discovery.enabled) {\n return [];\n }\n\n const provider = this.getEvmProvider();\n const { entropySource, groupIndex } = opts;\n\n const addressFromGroupIndex = await this.#getAddressFromGroupIndex({\n entropySource,\n groupIndex,\n });\n\n const count = await this.#getTransactionCount(\n provider,\n addressFromGroupIndex,\n );\n if (count === 0) {\n return [];\n }\n\n // We have some activity on this address, we try to create the account.\n const [address] = await this.#createAccount({\n entropySource,\n groupIndex,\n });\n assert(\n addressFromGroupIndex === address,\n 'Created account does not match address from group index.',\n );\n\n const account = this.messenger.call(\n 'AccountsController:getAccountByAddress',\n address,\n );\n assertInternalAccountExists(account);\n assertIsBip44Account(account);\n return [account];\n },\n );\n }\n\n async resyncAccounts(): Promise<void> {\n // No-op for the EVM account provider, since keyring accounts are already on\n // the MetaMask side.\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"EvmAccountProvider.mjs","sourceRoot":"","sources":["../../src/providers/EvmAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import { publicToAddress } from '@ethereumjs/util';\nimport type { Bip44Account } from '@metamask/account-api';\nimport { getUUIDFromAddressOfNormalAccount } from '@metamask/accounts-controller';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { HdKeyring } from '@metamask/eth-hd-keyring';\nimport type { EntropySourceId, KeyringAccount } from '@metamask/keyring-api';\nimport { EthAccountType } from '@metamask/keyring-api';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type {\n EthKeyring,\n InternalAccount,\n} from '@metamask/keyring-internal-api';\nimport type { Provider } from '@metamask/network-controller';\nimport { add0x, assert, bytesToHex, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport {\n assertAreBip44Accounts,\n assertIsBip44Account,\n BaseBip44AccountProvider,\n} from './BaseBip44AccountProvider';\nimport { withRetry, withTimeout } from './utils';\nimport { traceFallback } from '../analytics';\nimport { TraceName } from '../constants/traces';\nimport { projectLogger as log, WARNING_PREFIX } from '../logger';\nimport type { MultichainAccountServiceMessenger } from '../types';\n\nconst ETH_MAINNET_CHAIN_ID = '0x1';\n\n/**\n * Asserts an internal account exists.\n *\n * @param account - The internal account to check.\n * @throws An error if the internal account does not exist.\n */\nfunction assertInternalAccountExists(\n account: InternalAccount | undefined,\n): asserts account is InternalAccount {\n if (!account) {\n throw new Error('Internal account does not exist');\n }\n}\n\nexport type EvmAccountProviderConfig = {\n discovery: {\n enabled?: boolean;\n maxAttempts: number;\n timeoutMs: number;\n backOffMs: number;\n };\n};\n\nexport const EVM_ACCOUNT_PROVIDER_NAME = 'EVM';\n\nexport const EVM_ACCOUNT_PROVIDER_DEFAULT_CONFIG = {\n discovery: {\n maxAttempts: 3,\n timeoutMs: 500,\n backOffMs: 500,\n },\n};\n\nexport class EvmAccountProvider extends BaseBip44AccountProvider {\n static NAME = EVM_ACCOUNT_PROVIDER_NAME;\n\n readonly #config: EvmAccountProviderConfig;\n\n readonly #trace: TraceCallback;\n\n constructor(\n messenger: MultichainAccountServiceMessenger,\n config: EvmAccountProviderConfig = EVM_ACCOUNT_PROVIDER_DEFAULT_CONFIG,\n trace?: TraceCallback,\n ) {\n super(messenger);\n this.#config = {\n ...config,\n discovery: {\n ...config.discovery,\n enabled: config.discovery.enabled ?? true,\n },\n };\n this.#trace = trace ?? traceFallback;\n }\n\n isAccountCompatible(account: Bip44Account<InternalAccount>): boolean {\n return (\n account.type === EthAccountType.Eoa &&\n account.metadata.keyring.type === (KeyringTypes.hd as string)\n );\n }\n\n getName(): string {\n return EvmAccountProvider.NAME;\n }\n\n /**\n * Get the EVM provider.\n *\n * @returns The EVM provider.\n */\n getEvmProvider(): Provider {\n const networkClientId = this.messenger.call(\n 'NetworkController:findNetworkClientIdByChainId',\n ETH_MAINNET_CHAIN_ID,\n );\n const { provider } = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n return provider;\n }\n\n /**\n * Get the account ID for an EVM account.\n *\n * Note: Since the account ID is deterministic at the AccountsController level,\n * we can use this method to get the account ID from the address.\n *\n * @param address - The address of the account.\n * @returns The account ID.\n */\n #getAccountId(address: Hex): string {\n return getUUIDFromAddressOfNormalAccount(address);\n }\n\n /**\n * Create an EVM account.\n *\n * @param opts - The options for the creation of the account.\n * @param opts.entropySource - The entropy source to use for the creation of the account.\n * @param opts.groupIndex - The index of the group to create the account for.\n * @param opts.throwOnGap - Whether to throw an error if the account index is not contiguous.\n * @returns The account ID and a boolean indicating if the account was created.\n */\n async #createAccount({\n entropySource,\n groupIndex,\n throwOnGap = false,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n throwOnGap?: boolean;\n }): Promise<[Hex, boolean]> {\n const result = await this.withKeyring<EthKeyring, [Hex, boolean]>(\n { id: entropySource },\n async ({ keyring }) => {\n const existing = await keyring.getAccounts();\n if (groupIndex < existing.length) {\n return [existing[groupIndex], false];\n }\n\n // If the throwOnGap flag is set, we throw an error to prevent index gaps.\n if (throwOnGap && groupIndex !== existing.length) {\n throw new Error('Trying to create too many accounts');\n }\n\n const [added] = await keyring.addAccounts(1);\n return [added, true];\n },\n );\n\n return result;\n }\n\n /**\n * Create accounts for the EVM provider.\n *\n * @param opts - The options for the creation of the accounts.\n * @param opts.entropySource - The entropy source to use for the creation of the accounts.\n * @param opts.groupIndex - The index of the group to create the accounts for.\n * @returns The accounts for the EVM provider.\n */\n async createAccounts({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]> {\n const [address] = await this.#createAccount({\n entropySource,\n groupIndex,\n throwOnGap: true,\n });\n\n const accountId = this.#getAccountId(address);\n\n const account = this.messenger.call(\n 'AccountsController:getAccount',\n accountId,\n );\n\n // We MUST have the associated internal account.\n assertInternalAccountExists(account);\n\n const accountsArray = [account];\n assertAreBip44Accounts(accountsArray);\n\n this.accounts.add(account.id);\n return accountsArray;\n }\n\n /**\n * Get the transaction count for an EVM account.\n * This method uses a retry and timeout mechanism to handle transient failures.\n *\n * @param provider - The provider to use for the transaction count.\n * @param address - The address of the account.\n * @returns The transaction count.\n */\n async #getTransactionCount(\n provider: Provider,\n address: Hex,\n ): Promise<number> {\n const method = 'eth_getTransactionCount';\n\n const response = await withRetry(\n () =>\n withTimeout(\n provider.request({\n method,\n params: [address, 'latest'],\n }),\n this.#config.discovery.timeoutMs,\n ),\n {\n maxAttempts: this.#config.discovery.maxAttempts,\n backOffMs: this.#config.discovery.backOffMs,\n },\n );\n\n // Make sure we got the right response format, if not, we fallback to \"0x0\", to avoid having to deal with `NaN`.\n if (!isStrictHexString(response)) {\n const message = `Received invalid hex response from \"${method}\" request: ${JSON.stringify(response)}`;\n\n log(`${WARNING_PREFIX} ${message}`);\n console.warn(message);\n\n return 0;\n }\n\n return parseInt(response, 16);\n }\n\n async #getAddressFromGroupIndex({\n entropySource,\n groupIndex,\n }: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Hex> {\n // NOTE: To avoid exposing this function at keyring level, we just re-use its internal state\n // and compute the derivation here.\n return await this.withKeyring<HdKeyring, Hex>(\n { id: entropySource },\n async ({ keyring }) => {\n // If the account already exist, do not re-derive and just re-use that account.\n const existing = await keyring.getAccounts();\n if (groupIndex < existing.length) {\n return existing[groupIndex];\n }\n\n // If not, then we just \"peek\" the next address to avoid creating the account.\n assert(keyring.root, 'Expected HD keyring.root to be set');\n const hdKey = keyring.root.deriveChild(groupIndex);\n assert(hdKey.publicKey, 'Expected public key to be set');\n\n return add0x(\n bytesToHex(publicToAddress(hdKey.publicKey, true)).toLowerCase(),\n );\n },\n );\n }\n\n /**\n * Discover and create accounts for the EVM provider.\n *\n * @param opts - The options for the discovery and creation of accounts.\n * @param opts.entropySource - The entropy source to use for the discovery and creation of accounts.\n * @param opts.groupIndex - The index of the group to create the accounts for.\n * @returns The accounts for the EVM provider.\n */\n async discoverAccounts(opts: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]> {\n return this.#trace(\n {\n name: TraceName.EvmDiscoverAccounts,\n data: {\n provider: this.getName(),\n },\n },\n async () => {\n if (!this.#config.discovery.enabled) {\n return [];\n }\n\n const provider = this.getEvmProvider();\n const { entropySource, groupIndex } = opts;\n\n const addressFromGroupIndex = await this.#getAddressFromGroupIndex({\n entropySource,\n groupIndex,\n });\n\n const count = await this.#getTransactionCount(\n provider,\n addressFromGroupIndex,\n );\n if (count === 0) {\n return [];\n }\n\n // We have some activity on this address, we try to create the account.\n const [address] = await this.#createAccount({\n entropySource,\n groupIndex,\n });\n assert(\n addressFromGroupIndex === address,\n 'Created account does not match address from group index.',\n );\n\n const accoundId = this.#getAccountId(address);\n\n const account = this.messenger.call(\n 'AccountsController:getAccount',\n accoundId,\n );\n assertInternalAccountExists(account);\n assertIsBip44Account(account);\n this.accounts.add(account.id);\n return [account];\n },\n );\n }\n\n async resyncAccounts(): Promise<void> {\n // No-op for the EVM account provider, since keyring accounts are already on\n // the MetaMask side.\n }\n}\n"]}
|
|
@@ -10,7 +10,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
10
10
|
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");
|
|
11
11
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
12
|
};
|
|
13
|
-
var _SnapAccountProvider_instances, _SnapAccountProvider_queue, _SnapAccountProvider_trace, _SnapAccountProvider_getKeyringClientFromSnapId, _SnapAccountProvider_withSnapKeyring;
|
|
13
|
+
var _SnapAccountProvider_instances, _SnapAccountProvider_client, _SnapAccountProvider_queue, _SnapAccountProvider_trace, _SnapAccountProvider_getRestrictedSnapKeyring, _SnapAccountProvider_getKeyringClientFromSnapId, _SnapAccountProvider_withSnapKeyring;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.isSnapAccountProvider = exports.SnapAccountProvider = void 0;
|
|
16
16
|
const keyring_controller_1 = require("@metamask/keyring-controller");
|
|
@@ -26,10 +26,11 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
26
26
|
trace = analytics_1.traceFallback) {
|
|
27
27
|
super(messenger);
|
|
28
28
|
_SnapAccountProvider_instances.add(this);
|
|
29
|
+
_SnapAccountProvider_client.set(this, void 0);
|
|
29
30
|
_SnapAccountProvider_queue.set(this, void 0);
|
|
30
31
|
_SnapAccountProvider_trace.set(this, void 0);
|
|
31
32
|
this.snapId = snapId;
|
|
32
|
-
this
|
|
33
|
+
__classPrivateFieldSet(this, _SnapAccountProvider_client, __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_getKeyringClientFromSnapId).call(this, snapId), "f");
|
|
33
34
|
const maxConcurrency = config.maxConcurrency ?? Infinity;
|
|
34
35
|
this.config = {
|
|
35
36
|
...config,
|
|
@@ -45,6 +46,15 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
45
46
|
}
|
|
46
47
|
__classPrivateFieldSet(this, _SnapAccountProvider_trace, trace, "f");
|
|
47
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Ensures that the Snap platform is ready to be used.
|
|
51
|
+
*
|
|
52
|
+
* @returns A promise that resolves when the platform is ready.
|
|
53
|
+
* @throws An error if the platform is not ready (only effective once the platform has been ready at least once).
|
|
54
|
+
*/
|
|
55
|
+
async ensureCanUseSnapPlatform() {
|
|
56
|
+
return this.messenger.call('MultichainAccountService:ensureCanUseSnapPlatform');
|
|
57
|
+
}
|
|
48
58
|
/**
|
|
49
59
|
* Wraps an async operation with concurrency limiting based on maxConcurrency config.
|
|
50
60
|
* If maxConcurrency is Infinity (the default), the operation runs immediately without throttling.
|
|
@@ -62,65 +72,82 @@ class SnapAccountProvider extends BaseBip44AccountProvider_1.BaseBip44AccountPro
|
|
|
62
72
|
async trace(request, fn) {
|
|
63
73
|
return __classPrivateFieldGet(this, _SnapAccountProvider_trace, "f").call(this, request, fn);
|
|
64
74
|
}
|
|
65
|
-
async getRestrictedSnapAccountCreator() {
|
|
66
|
-
// NOTE: We're not supposed to make the keyring instance escape `withKeyring` but
|
|
67
|
-
// we have to use the `SnapKeyring` instance to be able to create Solana account
|
|
68
|
-
// without triggering UI confirmation.
|
|
69
|
-
// Also, creating account that way won't invalidate the Snap keyring state. The
|
|
70
|
-
// account will get created and persisted properly with the Snap account creation
|
|
71
|
-
// flow "asynchronously" (with `notify:accountCreated`).
|
|
72
|
-
const createAccount = await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, async ({ keyring }) => keyring.createAccount.bind(keyring));
|
|
73
|
-
return (options) => createAccount(this.snapId, options, {
|
|
74
|
-
displayAccountNameSuggestion: false,
|
|
75
|
-
displayConfirmation: false,
|
|
76
|
-
setSelectedAccount: false,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
75
|
async resyncAccounts(accounts) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
76
|
+
await this.withSnap(async ({ keyring }) => {
|
|
77
|
+
const localSnapAccounts = accounts.filter((account) => account.metadata.snap && account.metadata.snap.id === this.snapId);
|
|
78
|
+
const snapAccounts = new Set((await __classPrivateFieldGet(this, _SnapAccountProvider_client, "f").listAccounts()).map((account) => account.id));
|
|
79
|
+
// NOTE: This should never happen, but we want to report that kind of errors still
|
|
80
|
+
// in case states are de-sync.
|
|
81
|
+
if (localSnapAccounts.length < snapAccounts.size) {
|
|
82
|
+
this.messenger.captureException?.(new Error(`Snap "${this.snapId}" has de-synced accounts, Snap has more accounts than MetaMask!`));
|
|
83
|
+
// We don't recover from this case yet.
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// We want this part to be fast, so we only check for sizes, but we might need
|
|
87
|
+
// to make a real "diff" between the 2 states to not miss any de-sync.
|
|
88
|
+
if (localSnapAccounts.length > snapAccounts.size) {
|
|
89
|
+
// Accounts should never really be de-synced, so we want to log this to see how often this
|
|
90
|
+
// happens, cause that means that something else is buggy elsewhere...
|
|
91
|
+
this.messenger.captureException?.(new Error(`Snap "${this.snapId}" has de-synced accounts, we'll attempt to re-sync them...`));
|
|
92
|
+
// We always use the MetaMask list as the main reference here.
|
|
93
|
+
await Promise.all(localSnapAccounts.map(async (account) => {
|
|
94
|
+
const { id: entropySource, groupIndex } = account.options.entropy;
|
|
95
|
+
try {
|
|
96
|
+
if (!snapAccounts.has(account.id)) {
|
|
97
|
+
// We still need to remove the accounts from the Snap keyring since we're
|
|
98
|
+
// about to create the same account again, which will use a new ID, but will
|
|
99
|
+
// keep using the same address, and the Snap keyring does not allow this.
|
|
100
|
+
await keyring.removeAccount(account.address);
|
|
101
|
+
// The Snap has no account in its state for this one, we re-create it.
|
|
102
|
+
await this.createAccounts({
|
|
103
|
+
entropySource,
|
|
104
|
+
groupIndex,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
const sentryError = (0, utils_1.createSentryError)(`Unable to re-sync account: ${groupIndex}`, error, {
|
|
110
|
+
provider: this.getName(),
|
|
107
111
|
groupIndex,
|
|
108
112
|
});
|
|
113
|
+
this.messenger.captureException?.(sentryError);
|
|
109
114
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
async withSnap(operation) {
|
|
120
|
+
await this.ensureCanUseSnapPlatform();
|
|
121
|
+
return await operation({
|
|
122
|
+
client: __classPrivateFieldGet(this, _SnapAccountProvider_client, "f"),
|
|
123
|
+
keyring: await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_getRestrictedSnapKeyring).call(this),
|
|
124
|
+
});
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
exports.SnapAccountProvider = SnapAccountProvider;
|
|
123
|
-
_SnapAccountProvider_queue = new WeakMap(), _SnapAccountProvider_trace = new WeakMap(), _SnapAccountProvider_instances = new WeakSet(),
|
|
128
|
+
_SnapAccountProvider_client = new WeakMap(), _SnapAccountProvider_queue = new WeakMap(), _SnapAccountProvider_trace = new WeakMap(), _SnapAccountProvider_instances = new WeakSet(), _SnapAccountProvider_getRestrictedSnapKeyring = async function _SnapAccountProvider_getRestrictedSnapKeyring() {
|
|
129
|
+
// NOTE: We're not supposed to make the keyring instance escape `withKeyring` but
|
|
130
|
+
// we have to use the `SnapKeyring` instance to be able to create Solana account
|
|
131
|
+
// without triggering UI confirmation.
|
|
132
|
+
// Also, creating account that way won't invalidate the Snap keyring state. The
|
|
133
|
+
// account will get created and persisted properly with the Snap account creation
|
|
134
|
+
// flow "asynchronously" (with `notify:accountCreated`).
|
|
135
|
+
const createAccount = await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, async ({ keyring }) => keyring.createAccount.bind(keyring));
|
|
136
|
+
return {
|
|
137
|
+
createAccount: async (options) =>
|
|
138
|
+
// We use the "unguarded" account creation here (see explanation above).
|
|
139
|
+
await createAccount(this.snapId, options, {
|
|
140
|
+
displayAccountNameSuggestion: false,
|
|
141
|
+
displayConfirmation: false,
|
|
142
|
+
setSelectedAccount: false,
|
|
143
|
+
}),
|
|
144
|
+
removeAccount: async (address) =>
|
|
145
|
+
// Though, when removing account, we can use the normal flow.
|
|
146
|
+
await __classPrivateFieldGet(this, _SnapAccountProvider_instances, "m", _SnapAccountProvider_withSnapKeyring).call(this, async ({ keyring }) => {
|
|
147
|
+
await keyring.removeAccount(address);
|
|
148
|
+
}),
|
|
149
|
+
};
|
|
150
|
+
}, _SnapAccountProvider_getKeyringClientFromSnapId = function _SnapAccountProvider_getKeyringClientFromSnapId(snapId) {
|
|
124
151
|
return new keyring_snap_client_1.KeyringClient({
|
|
125
152
|
send: async (request) => {
|
|
126
153
|
const response = await this.messenger.call('SnapController:handleRequest', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport type { TraceCallback, TraceRequest } from '@metamask/controller-utils';\nimport type { SnapKeyring } from '@metamask/eth-snap-keyring';\nimport type { EntropySourceId, KeyringAccount } from '@metamask/keyring-api';\nimport type { KeyringMetadata } from '@metamask/keyring-controller';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { Json, JsonRpcRequest, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { Semaphore } from 'async-mutex';\n\nimport { BaseBip44AccountProvider } from './BaseBip44AccountProvider';\nimport { traceFallback } from '../analytics';\nimport type { MultichainAccountServiceMessenger } from '../types';\nimport { createSentryError } from '../utils';\n\nexport type RestrictedSnapKeyringCreateAccount = (\n options: Record<string, Json>,\n) => Promise<KeyringAccount>;\n\nexport type SnapAccountProviderConfig = {\n maxConcurrency?: number;\n discovery: {\n enabled?: boolean;\n maxAttempts: number;\n timeoutMs: number;\n backOffMs: number;\n };\n createAccounts: {\n timeoutMs: number;\n };\n};\n\nexport abstract class SnapAccountProvider extends BaseBip44AccountProvider {\n readonly snapId: SnapId;\n\n protected readonly config: SnapAccountProviderConfig;\n\n protected readonly client: KeyringClient;\n\n readonly #queue?: Semaphore;\n\n readonly #trace: TraceCallback;\n\n constructor(\n snapId: SnapId,\n messenger: MultichainAccountServiceMessenger,\n config: SnapAccountProviderConfig,\n /* istanbul ignore next */\n trace: TraceCallback = traceFallback,\n ) {\n super(messenger);\n\n this.snapId = snapId;\n this.client = this.#getKeyringClientFromSnapId(snapId);\n\n const maxConcurrency = config.maxConcurrency ?? Infinity;\n this.config = {\n ...config,\n discovery: {\n ...config.discovery,\n enabled: config.discovery.enabled ?? true,\n },\n maxConcurrency,\n };\n\n // Create semaphore only if concurrency is limited\n if (isFinite(maxConcurrency)) {\n this.#queue = new Semaphore(maxConcurrency);\n }\n\n this.#trace = trace;\n }\n\n /**\n * Wraps an async operation with concurrency limiting based on maxConcurrency config.\n * If maxConcurrency is Infinity (the default), the operation runs immediately without throttling.\n * Otherwise, it's queued through the semaphore to respect the concurrency limit.\n *\n * @param operation - The async operation to execute.\n * @returns The result of the operation.\n */\n protected async withMaxConcurrency<T>(\n operation: () => Promise<T>,\n ): Promise<T> {\n if (this.#queue) {\n return this.#queue.runExclusive(operation);\n }\n return operation();\n }\n\n protected async trace<ReturnType>(\n request: TraceRequest,\n fn: () => Promise<ReturnType>,\n ): Promise<ReturnType> {\n return this.#trace(request, fn);\n }\n\n protected async getRestrictedSnapAccountCreator(): Promise<RestrictedSnapKeyringCreateAccount> {\n // NOTE: We're not supposed to make the keyring instance escape `withKeyring` but\n // we have to use the `SnapKeyring` instance to be able to create Solana account\n // without triggering UI confirmation.\n // Also, creating account that way won't invalidate the Snap keyring state. The\n // account will get created and persisted properly with the Snap account creation\n // flow \"asynchronously\" (with `notify:accountCreated`).\n const createAccount = await this.#withSnapKeyring<\n SnapKeyring['createAccount']\n >(async ({ keyring }) => keyring.createAccount.bind(keyring));\n\n return (options) =>\n createAccount(this.snapId, options, {\n displayAccountNameSuggestion: false,\n displayConfirmation: false,\n setSelectedAccount: false,\n });\n }\n\n #getKeyringClientFromSnapId(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest) => {\n const response = await this.messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n },\n );\n return response as Json;\n },\n });\n }\n\n async resyncAccounts(\n accounts: Bip44Account<InternalAccount>[],\n ): Promise<void> {\n const localSnapAccounts = accounts.filter(\n (account) =>\n account.metadata.snap && account.metadata.snap.id === this.snapId,\n );\n const snapAccounts = new Set(\n (await this.client.listAccounts()).map((account) => account.id),\n );\n\n // NOTE: This should never happen, but we want to report that kind of errors still\n // in case states are de-sync.\n if (localSnapAccounts.length < snapAccounts.size) {\n this.messenger.captureException?.(\n new Error(\n `Snap \"${this.snapId}\" has de-synced accounts, Snap has more accounts than MetaMask!`,\n ),\n );\n\n // We don't recover from this case yet.\n return;\n }\n\n // We want this part to be fast, so we only check for sizes, but we might need\n // to make a real \"diff\" between the 2 states to not miss any de-sync.\n if (localSnapAccounts.length > snapAccounts.size) {\n // Accounts should never really be de-synced, so we want to log this to see how often this\n // happens, cause that means that something else is buggy elsewhere...\n this.messenger.captureException?.(\n new Error(\n `Snap \"${this.snapId}\" has de-synced accounts, we'll attempt to re-sync them...`,\n ),\n );\n\n // We always use the MetaMask list as the main reference here.\n await Promise.all(\n localSnapAccounts.map(async (account) => {\n const { id: entropySource, groupIndex } = account.options.entropy;\n\n try {\n if (!snapAccounts.has(account.id)) {\n // We still need to remove the accounts from the Snap keyring since we're\n // about to create the same account again, which will use a new ID, but will\n // keep using the same address, and the Snap keyring does not allow this.\n await this.#withSnapKeyring(\n async ({ keyring }) =>\n await keyring.removeAccount(account.address),\n );\n\n // The Snap has no account in its state for this one, we re-create it.\n await this.createAccounts({\n entropySource,\n groupIndex,\n });\n }\n } catch (error) {\n const sentryError = createSentryError(\n `Unable to re-sync account: ${groupIndex}`,\n error as Error,\n {\n provider: this.getName(),\n groupIndex,\n },\n );\n this.messenger.captureException?.(sentryError);\n }\n }),\n );\n }\n }\n\n async #withSnapKeyring<CallbackResult = void>(\n operation: ({\n keyring,\n metadata,\n }: {\n keyring: SnapKeyring;\n metadata: KeyringMetadata;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n return this.withKeyring<SnapKeyring, CallbackResult>(\n { type: KeyringTypes.snap },\n (args) => {\n return operation(args);\n },\n );\n }\n\n abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;\n\n abstract createAccounts(options: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]>;\n\n abstract discoverAccounts(options: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]>;\n}\n\nexport const isSnapAccountProvider = (\n provider: unknown,\n): provider is SnapAccountProvider => {\n return provider instanceof SnapAccountProvider;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"SnapAccountProvider.cjs","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Bip44Account } from '@metamask/account-api';\nimport type { TraceCallback, TraceRequest } from '@metamask/controller-utils';\nimport type { SnapKeyring } from '@metamask/eth-snap-keyring';\nimport type { EntropySourceId, KeyringAccount } from '@metamask/keyring-api';\nimport type { KeyringMetadata } from '@metamask/keyring-controller';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type { Json, JsonRpcRequest, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { Semaphore } from 'async-mutex';\n\nimport { BaseBip44AccountProvider } from './BaseBip44AccountProvider';\nimport { traceFallback } from '../analytics';\nimport type { MultichainAccountServiceMessenger } from '../types';\nimport { createSentryError } from '../utils';\n\nexport type RestrictedSnapKeyring = {\n createAccount: (options: Record<string, Json>) => Promise<KeyringAccount>;\n removeAccount: (address: string) => Promise<void>;\n};\n\nexport type SnapAccountProviderConfig = {\n maxConcurrency?: number;\n discovery: {\n enabled?: boolean;\n maxAttempts: number;\n timeoutMs: number;\n backOffMs: number;\n };\n createAccounts: {\n timeoutMs: number;\n };\n};\n\nexport abstract class SnapAccountProvider extends BaseBip44AccountProvider {\n readonly snapId: SnapId;\n\n protected readonly config: SnapAccountProviderConfig;\n\n readonly #client: KeyringClient;\n\n readonly #queue?: Semaphore;\n\n readonly #trace: TraceCallback;\n\n constructor(\n snapId: SnapId,\n messenger: MultichainAccountServiceMessenger,\n config: SnapAccountProviderConfig,\n /* istanbul ignore next */\n trace: TraceCallback = traceFallback,\n ) {\n super(messenger);\n\n this.snapId = snapId;\n this.#client = this.#getKeyringClientFromSnapId(snapId);\n\n const maxConcurrency = config.maxConcurrency ?? Infinity;\n this.config = {\n ...config,\n discovery: {\n ...config.discovery,\n enabled: config.discovery.enabled ?? true,\n },\n maxConcurrency,\n };\n\n // Create semaphore only if concurrency is limited\n if (isFinite(maxConcurrency)) {\n this.#queue = new Semaphore(maxConcurrency);\n }\n\n this.#trace = trace;\n }\n\n /**\n * Ensures that the Snap platform is ready to be used.\n *\n * @returns A promise that resolves when the platform is ready.\n * @throws An error if the platform is not ready (only effective once the platform has been ready at least once).\n */\n async ensureCanUseSnapPlatform(): Promise<void> {\n return this.messenger.call(\n 'MultichainAccountService:ensureCanUseSnapPlatform',\n );\n }\n\n /**\n * Wraps an async operation with concurrency limiting based on maxConcurrency config.\n * If maxConcurrency is Infinity (the default), the operation runs immediately without throttling.\n * Otherwise, it's queued through the semaphore to respect the concurrency limit.\n *\n * @param operation - The async operation to execute.\n * @returns The result of the operation.\n */\n protected async withMaxConcurrency<Result>(\n operation: () => Promise<Result>,\n ): Promise<Result> {\n if (this.#queue) {\n return this.#queue.runExclusive(operation);\n }\n return operation();\n }\n\n protected async trace<ReturnType>(\n request: TraceRequest,\n fn: () => Promise<ReturnType>,\n ): Promise<ReturnType> {\n return this.#trace(request, fn);\n }\n\n async #getRestrictedSnapKeyring(): Promise<RestrictedSnapKeyring> {\n // NOTE: We're not supposed to make the keyring instance escape `withKeyring` but\n // we have to use the `SnapKeyring` instance to be able to create Solana account\n // without triggering UI confirmation.\n // Also, creating account that way won't invalidate the Snap keyring state. The\n // account will get created and persisted properly with the Snap account creation\n // flow \"asynchronously\" (with `notify:accountCreated`).\n const createAccount = await this.#withSnapKeyring<\n SnapKeyring['createAccount']\n >(async ({ keyring }) => keyring.createAccount.bind(keyring));\n\n return {\n createAccount: async (options) =>\n // We use the \"unguarded\" account creation here (see explanation above).\n await createAccount(this.snapId, options, {\n displayAccountNameSuggestion: false,\n displayConfirmation: false,\n setSelectedAccount: false,\n }),\n removeAccount: async (address: string) =>\n // Though, when removing account, we can use the normal flow.\n await this.#withSnapKeyring(async ({ keyring }) => {\n await keyring.removeAccount(address);\n }),\n };\n }\n\n #getKeyringClientFromSnapId(snapId: string): KeyringClient {\n return new KeyringClient({\n send: async (request: JsonRpcRequest): Promise<Json> => {\n const response = await this.messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n },\n );\n return response as Json;\n },\n });\n }\n\n async resyncAccounts(\n accounts: Bip44Account<InternalAccount>[],\n ): Promise<void> {\n await this.withSnap(async ({ keyring }) => {\n const localSnapAccounts = accounts.filter(\n (account) =>\n account.metadata.snap && account.metadata.snap.id === this.snapId,\n );\n const snapAccounts = new Set(\n (await this.#client.listAccounts()).map((account) => account.id),\n );\n\n // NOTE: This should never happen, but we want to report that kind of errors still\n // in case states are de-sync.\n if (localSnapAccounts.length < snapAccounts.size) {\n this.messenger.captureException?.(\n new Error(\n `Snap \"${this.snapId}\" has de-synced accounts, Snap has more accounts than MetaMask!`,\n ),\n );\n\n // We don't recover from this case yet.\n return;\n }\n\n // We want this part to be fast, so we only check for sizes, but we might need\n // to make a real \"diff\" between the 2 states to not miss any de-sync.\n if (localSnapAccounts.length > snapAccounts.size) {\n // Accounts should never really be de-synced, so we want to log this to see how often this\n // happens, cause that means that something else is buggy elsewhere...\n this.messenger.captureException?.(\n new Error(\n `Snap \"${this.snapId}\" has de-synced accounts, we'll attempt to re-sync them...`,\n ),\n );\n\n // We always use the MetaMask list as the main reference here.\n await Promise.all(\n localSnapAccounts.map(async (account) => {\n const { id: entropySource, groupIndex } = account.options.entropy;\n\n try {\n if (!snapAccounts.has(account.id)) {\n // We still need to remove the accounts from the Snap keyring since we're\n // about to create the same account again, which will use a new ID, but will\n // keep using the same address, and the Snap keyring does not allow this.\n await keyring.removeAccount(account.address);\n // The Snap has no account in its state for this one, we re-create it.\n await this.createAccounts({\n entropySource,\n groupIndex,\n });\n }\n } catch (error) {\n const sentryError = createSentryError(\n `Unable to re-sync account: ${groupIndex}`,\n error as Error,\n {\n provider: this.getName(),\n groupIndex,\n },\n );\n this.messenger.captureException?.(sentryError);\n }\n }),\n );\n }\n });\n }\n\n async #withSnapKeyring<CallbackResult = void>(\n operation: ({\n keyring,\n metadata,\n }: {\n keyring: SnapKeyring;\n metadata: KeyringMetadata;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n return this.withKeyring<SnapKeyring, CallbackResult>(\n { type: KeyringTypes.snap },\n (args) => {\n return operation(args);\n },\n );\n }\n\n protected async withSnap<CallbackResult = void>(\n operation: (snap: {\n client: KeyringClient;\n keyring: RestrictedSnapKeyring;\n }) => Promise<CallbackResult>,\n ): Promise<CallbackResult> {\n await this.ensureCanUseSnapPlatform();\n\n return await operation({\n client: this.#client,\n keyring: await this.#getRestrictedSnapKeyring(),\n });\n }\n\n abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;\n\n abstract createAccounts(options: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]>;\n\n abstract discoverAccounts(options: {\n entropySource: EntropySourceId;\n groupIndex: number;\n }): Promise<Bip44Account<KeyringAccount>[]>;\n}\n\nexport const isSnapAccountProvider = (\n provider: unknown,\n): provider is SnapAccountProvider => {\n return provider instanceof SnapAccountProvider;\n};\n"]}
|
|
@@ -6,7 +6,10 @@ import { KeyringClient } from "@metamask/keyring-snap-client";
|
|
|
6
6
|
import type { Json, SnapId } from "@metamask/snaps-sdk";
|
|
7
7
|
import { BaseBip44AccountProvider } from "./BaseBip44AccountProvider.cjs";
|
|
8
8
|
import type { MultichainAccountServiceMessenger } from "../types.cjs";
|
|
9
|
-
export type
|
|
9
|
+
export type RestrictedSnapKeyring = {
|
|
10
|
+
createAccount: (options: Record<string, Json>) => Promise<KeyringAccount>;
|
|
11
|
+
removeAccount: (address: string) => Promise<void>;
|
|
12
|
+
};
|
|
10
13
|
export type SnapAccountProviderConfig = {
|
|
11
14
|
maxConcurrency?: number;
|
|
12
15
|
discovery: {
|
|
@@ -23,8 +26,14 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
23
26
|
#private;
|
|
24
27
|
readonly snapId: SnapId;
|
|
25
28
|
protected readonly config: SnapAccountProviderConfig;
|
|
26
|
-
protected readonly client: KeyringClient;
|
|
27
29
|
constructor(snapId: SnapId, messenger: MultichainAccountServiceMessenger, config: SnapAccountProviderConfig, trace?: TraceCallback);
|
|
30
|
+
/**
|
|
31
|
+
* Ensures that the Snap platform is ready to be used.
|
|
32
|
+
*
|
|
33
|
+
* @returns A promise that resolves when the platform is ready.
|
|
34
|
+
* @throws An error if the platform is not ready (only effective once the platform has been ready at least once).
|
|
35
|
+
*/
|
|
36
|
+
ensureCanUseSnapPlatform(): Promise<void>;
|
|
28
37
|
/**
|
|
29
38
|
* Wraps an async operation with concurrency limiting based on maxConcurrency config.
|
|
30
39
|
* If maxConcurrency is Infinity (the default), the operation runs immediately without throttling.
|
|
@@ -33,10 +42,13 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
33
42
|
* @param operation - The async operation to execute.
|
|
34
43
|
* @returns The result of the operation.
|
|
35
44
|
*/
|
|
36
|
-
protected withMaxConcurrency<
|
|
45
|
+
protected withMaxConcurrency<Result>(operation: () => Promise<Result>): Promise<Result>;
|
|
37
46
|
protected trace<ReturnType>(request: TraceRequest, fn: () => Promise<ReturnType>): Promise<ReturnType>;
|
|
38
|
-
protected getRestrictedSnapAccountCreator(): Promise<RestrictedSnapKeyringCreateAccount>;
|
|
39
47
|
resyncAccounts(accounts: Bip44Account<InternalAccount>[]): Promise<void>;
|
|
48
|
+
protected withSnap<CallbackResult = void>(operation: (snap: {
|
|
49
|
+
client: KeyringClient;
|
|
50
|
+
keyring: RestrictedSnapKeyring;
|
|
51
|
+
}) => Promise<CallbackResult>): Promise<CallbackResult>;
|
|
40
52
|
abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;
|
|
41
53
|
abstract createAccounts(options: {
|
|
42
54
|
entropySource: EntropySourceId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountProvider.d.cts","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,mCAAmC;AAE9E,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,8BAA8B;AAG7E,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,EAAE,aAAa,EAAE,sCAAsC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,EAAE,4BAA4B;AAIxE,OAAO,EAAE,wBAAwB,EAAE,uCAAmC;AAEtE,OAAO,KAAK,EAAE,iCAAiC,EAAE,qBAAiB;AAGlE,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"SnapAccountProvider.d.cts","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,mCAAmC;AAE9E,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,8BAA8B;AAG7E,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,EAAE,aAAa,EAAE,sCAAsC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,EAAE,4BAA4B;AAIxE,OAAO,EAAE,wBAAwB,EAAE,uCAAmC;AAEtE,OAAO,KAAK,EAAE,iCAAiC,EAAE,qBAAiB;AAGlE,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1E,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE;QACT,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,cAAc,EAAE;QACd,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,8BAAsB,mBAAoB,SAAQ,wBAAwB;;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;gBASnD,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,iCAAiC,EAC5C,MAAM,EAAE,yBAAyB,EAEjC,KAAK,GAAE,aAA6B;IAyBtC;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/C;;;;;;;OAOG;cACa,kBAAkB,CAAC,MAAM,EACvC,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAC/B,OAAO,CAAC,MAAM,CAAC;cAOF,KAAK,CAAC,UAAU,EAC9B,OAAO,EAAE,YAAY,EACrB,EAAE,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC;IAgDhB,cAAc,CAClB,QAAQ,EAAE,YAAY,CAAC,eAAe,CAAC,EAAE,GACxC,OAAO,CAAC,IAAI,CAAC;cAqFA,QAAQ,CAAC,cAAc,GAAG,IAAI,EAC5C,SAAS,EAAE,CAAC,IAAI,EAAE;QAChB,MAAM,EAAE,aAAa,CAAC;QACtB,OAAO,EAAE,qBAAqB,CAAC;KAChC,KAAK,OAAO,CAAC,cAAc,CAAC,GAC5B,OAAO,CAAC,cAAc,CAAC;IAS1B,QAAQ,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,eAAe,CAAC,GAAG,OAAO;IAE7E,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE;QAC/B,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAE3C,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE;QACjC,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;CAC5C;AAED,eAAO,MAAM,qBAAqB,aACtB,OAAO,oCAGlB,CAAC"}
|
|
@@ -6,7 +6,10 @@ import { KeyringClient } from "@metamask/keyring-snap-client";
|
|
|
6
6
|
import type { Json, SnapId } from "@metamask/snaps-sdk";
|
|
7
7
|
import { BaseBip44AccountProvider } from "./BaseBip44AccountProvider.mjs";
|
|
8
8
|
import type { MultichainAccountServiceMessenger } from "../types.mjs";
|
|
9
|
-
export type
|
|
9
|
+
export type RestrictedSnapKeyring = {
|
|
10
|
+
createAccount: (options: Record<string, Json>) => Promise<KeyringAccount>;
|
|
11
|
+
removeAccount: (address: string) => Promise<void>;
|
|
12
|
+
};
|
|
10
13
|
export type SnapAccountProviderConfig = {
|
|
11
14
|
maxConcurrency?: number;
|
|
12
15
|
discovery: {
|
|
@@ -23,8 +26,14 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
23
26
|
#private;
|
|
24
27
|
readonly snapId: SnapId;
|
|
25
28
|
protected readonly config: SnapAccountProviderConfig;
|
|
26
|
-
protected readonly client: KeyringClient;
|
|
27
29
|
constructor(snapId: SnapId, messenger: MultichainAccountServiceMessenger, config: SnapAccountProviderConfig, trace?: TraceCallback);
|
|
30
|
+
/**
|
|
31
|
+
* Ensures that the Snap platform is ready to be used.
|
|
32
|
+
*
|
|
33
|
+
* @returns A promise that resolves when the platform is ready.
|
|
34
|
+
* @throws An error if the platform is not ready (only effective once the platform has been ready at least once).
|
|
35
|
+
*/
|
|
36
|
+
ensureCanUseSnapPlatform(): Promise<void>;
|
|
28
37
|
/**
|
|
29
38
|
* Wraps an async operation with concurrency limiting based on maxConcurrency config.
|
|
30
39
|
* If maxConcurrency is Infinity (the default), the operation runs immediately without throttling.
|
|
@@ -33,10 +42,13 @@ export declare abstract class SnapAccountProvider extends BaseBip44AccountProvid
|
|
|
33
42
|
* @param operation - The async operation to execute.
|
|
34
43
|
* @returns The result of the operation.
|
|
35
44
|
*/
|
|
36
|
-
protected withMaxConcurrency<
|
|
45
|
+
protected withMaxConcurrency<Result>(operation: () => Promise<Result>): Promise<Result>;
|
|
37
46
|
protected trace<ReturnType>(request: TraceRequest, fn: () => Promise<ReturnType>): Promise<ReturnType>;
|
|
38
|
-
protected getRestrictedSnapAccountCreator(): Promise<RestrictedSnapKeyringCreateAccount>;
|
|
39
47
|
resyncAccounts(accounts: Bip44Account<InternalAccount>[]): Promise<void>;
|
|
48
|
+
protected withSnap<CallbackResult = void>(operation: (snap: {
|
|
49
|
+
client: KeyringClient;
|
|
50
|
+
keyring: RestrictedSnapKeyring;
|
|
51
|
+
}) => Promise<CallbackResult>): Promise<CallbackResult>;
|
|
40
52
|
abstract isAccountCompatible(account: Bip44Account<InternalAccount>): boolean;
|
|
41
53
|
abstract createAccounts(options: {
|
|
42
54
|
entropySource: EntropySourceId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapAccountProvider.d.mts","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,mCAAmC;AAE9E,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,8BAA8B;AAG7E,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,EAAE,aAAa,EAAE,sCAAsC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,EAAE,4BAA4B;AAIxE,OAAO,EAAE,wBAAwB,EAAE,uCAAmC;AAEtE,OAAO,KAAK,EAAE,iCAAiC,EAAE,qBAAiB;AAGlE,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"SnapAccountProvider.d.mts","sourceRoot":"","sources":["../../src/providers/SnapAccountProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,mCAAmC;AAE9E,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,8BAA8B;AAG7E,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,EAAE,aAAa,EAAE,sCAAsC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,EAAE,4BAA4B;AAIxE,OAAO,EAAE,wBAAwB,EAAE,uCAAmC;AAEtE,OAAO,KAAK,EAAE,iCAAiC,EAAE,qBAAiB;AAGlE,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1E,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE;QACT,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,cAAc,EAAE;QACd,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,8BAAsB,mBAAoB,SAAQ,wBAAwB;;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;gBASnD,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,iCAAiC,EAC5C,MAAM,EAAE,yBAAyB,EAEjC,KAAK,GAAE,aAA6B;IAyBtC;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IAM/C;;;;;;;OAOG;cACa,kBAAkB,CAAC,MAAM,EACvC,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAC/B,OAAO,CAAC,MAAM,CAAC;cAOF,KAAK,CAAC,UAAU,EAC9B,OAAO,EAAE,YAAY,EACrB,EAAE,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAC5B,OAAO,CAAC,UAAU,CAAC;IAgDhB,cAAc,CAClB,QAAQ,EAAE,YAAY,CAAC,eAAe,CAAC,EAAE,GACxC,OAAO,CAAC,IAAI,CAAC;cAqFA,QAAQ,CAAC,cAAc,GAAG,IAAI,EAC5C,SAAS,EAAE,CAAC,IAAI,EAAE;QAChB,MAAM,EAAE,aAAa,CAAC;QACtB,OAAO,EAAE,qBAAqB,CAAC;KAChC,KAAK,OAAO,CAAC,cAAc,CAAC,GAC5B,OAAO,CAAC,cAAc,CAAC;IAS1B,QAAQ,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,eAAe,CAAC,GAAG,OAAO;IAE7E,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE;QAC/B,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;IAE3C,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE;QACjC,aAAa,EAAE,eAAe,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;CAC5C;AAED,eAAO,MAAM,qBAAqB,aACtB,OAAO,oCAGlB,CAAC"}
|