@metamask/snaps-rpc-methods
Version:
MetaMask Snaps JSON-RPC method implementations
1 lines • 10.3 kB
Source Map (JSON)
{"version":3,"file":"getBip32Entropy.mjs","sourceRoot":"","sources":["../../src/restricted/getBip32Entropy.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CryptographicFunctions } from '@metamask/key-tree';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n PermissionSpecificationBuilder,\n PermissionValidatorConstraint,\n RestrictedMethodOptions,\n ValidPermissionSpecification,\n} from '@metamask/permission-controller';\nimport { PermissionType, SubjectType } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type {\n GetBip32EntropyParams,\n GetBip32EntropyResult,\n} from '@metamask/snaps-sdk';\nimport { SnapCaveatType } from '@metamask/snaps-utils';\nimport type { NonEmptyArray } from '@metamask/utils';\nimport { assert } from '@metamask/utils';\n\nimport type { KeyringControllerWithKeyringV2UnsafeAction } from '../types';\nimport type { MethodHooksObject } from '../utils';\nimport {\n getMnemonic,\n getMnemonicSeed,\n getNodeFromMnemonic,\n getNodeFromSeed,\n getValueFromEntropySource,\n} from '../utils';\n\nconst targetName = 'snap_getBip32Entropy';\n\nexport type GetBip32EntropyMethodHooks = {\n /**\n * Waits for the extension to be unlocked.\n *\n * @returns A promise that resolves once the extension is unlocked.\n */\n getUnlockPromise: (shouldShowUnlockRequest: boolean) => Promise<void>;\n\n /**\n * Get the cryptographic functions to use for the client. This may return an\n * empty object or `undefined` to fall back to the default cryptographic\n * functions.\n *\n * @returns The cryptographic functions to use for the client.\n */\n getClientCryptography: () => CryptographicFunctions | undefined;\n};\n\nexport type GetBip32EntropyMessengerActions =\n KeyringControllerWithKeyringV2UnsafeAction;\n\ntype GetBip32EntropySpecificationBuilderOptions = {\n methodHooks: GetBip32EntropyMethodHooks;\n messenger: Messenger<string, GetBip32EntropyMessengerActions>;\n};\n\ntype GetBip32EntropySpecification = ValidPermissionSpecification<{\n permissionType: PermissionType.RestrictedMethod;\n targetName: typeof targetName;\n methodImplementation: ReturnType<typeof getBip32EntropyImplementation>;\n allowedCaveats: Readonly<NonEmptyArray<string>> | null;\n validator: PermissionValidatorConstraint;\n}>;\n\n/**\n * The specification builder for the `snap_getBip32Entropy` permission.\n * `snap_getBip32Entropy` lets the Snap control private keys for a particular\n * BIP-32 node.\n *\n * @param options - The specification builder options.\n * @param options.messenger - The messenger.\n * @param options.methodHooks - The RPC method hooks needed by the method implementation.\n * @returns The specification for the `snap_getBip32Entropy` permission.\n */\nconst specificationBuilder: PermissionSpecificationBuilder<\n PermissionType.RestrictedMethod,\n GetBip32EntropySpecificationBuilderOptions,\n GetBip32EntropySpecification\n> = ({\n methodHooks,\n messenger,\n}: GetBip32EntropySpecificationBuilderOptions) => {\n return {\n permissionType: PermissionType.RestrictedMethod,\n targetName,\n allowedCaveats: [SnapCaveatType.PermittedDerivationPaths],\n methodImplementation: getBip32EntropyImplementation({\n methodHooks,\n messenger,\n }),\n validator: ({ caveats }) => {\n if (\n caveats?.length !== 1 ||\n caveats[0].type !== SnapCaveatType.PermittedDerivationPaths\n ) {\n throw rpcErrors.invalidParams({\n message: `Expected a single \"${SnapCaveatType.PermittedDerivationPaths}\" caveat.`,\n });\n }\n },\n subjectTypes: [SubjectType.Snap],\n };\n};\n\nconst methodHooks: MethodHooksObject<GetBip32EntropyMethodHooks> = {\n getUnlockPromise: true,\n getClientCryptography: true,\n};\n\n/**\n * Enables you to [manage users' non-EVM accounts](https://docs.metamask.io/snaps/features/non-evm-networks/)\n * by deriving the [SLIP-10](https://github.com/satoshilabs/slips/blob/master/slip-0010.md)\n * keys specified by the `path` and `curve` parameters. The keys are derived\n * using the entropy from the user's Secret Recovery Phrase.\n *\n * If the keys you want to derive conform to the [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)\n * structure, use [snap_getBip44Entropy](https://docs.metamask.io/snaps/reference/snaps-api/snap_getbip44entropy)\n * instead. Otherwise, use this method.\n *\n * This method is designed to be used with the [`@metamask/key-tree`](https://npmjs.com/package/@metamask/key-tree)\n * module. `@metamask/key-tree` can help you get the [extended private keys](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#extended-keys)\n * for user addresses, but it's your responsibility to know how to use those\n * keys to, for example, derive an address for the relevant protocol or sign a\n * transaction for the user.\n *\n * @example\n * ```json name=\"Manifest\"\n * {\n * \"initialPermissions\": {\n * \"snap_getBip32Entropy\": [\n * {\n * \"path\": [\"m\", \"44'\", \"3'\"],\n * \"curve\": \"secp256k1\" // Or \"ed25519\", \"ed25519Bip32\"\n * }\n * ]\n * }\n * }\n * ```\n * ```ts name=\"Usage\"\n * import { SLIP10Node } from '@metamask/key-tree'\n *\n * // This example uses Dogecoin, which has a derivation path starting with\n * // m/44'/3'.\n * const dogecoinNode = await snap.request({\n * method: 'snap_getBip32Entropy',\n * params: {\n * // The path and curve must be specified in the initial permissions.\n * path: ['m', \"44'\", \"3'\"],\n * curve: 'secp256k1',\n * },\n * })\n *\n * // Next, create an instance of a SLIP-10 node for the Dogecoin node.\n * const dogecoinSlip10Node = await SLIP10Node.fromJSON(dogecoinNode)\n *\n * // m/44'/3'/0'\n * const accountKey0 = await dogecoinSlip10Node.derive([\"bip32:0'\"])\n *\n * // m/44'/3'/1'\n * const accountKey1 = await dogecoinSlip10Node.derive([\"bip32:1'\"])\n *\n * // Now, you can ask the user to sign transactions, etc.\n * ```\n */\nexport const getBip32EntropyBuilder = Object.freeze({\n targetName,\n specificationBuilder,\n methodHooks,\n actionNames: ['KeyringController:withKeyringV2Unsafe'],\n} as const);\n\n/**\n * Builds the method implementation for `snap_getBip32Entropy`.\n *\n * @param options - The options.\n * @param options.messenger - The messenger.\n * @param options.methodHooks - The RPC method hooks.\n * @param options.methodHooks.getUnlockPromise - A function that resolves once the MetaMask extension is unlocked\n * and prompts the user to unlock their MetaMask if it is locked.\n * @param options.methodHooks.getClientCryptography - A function to retrieve the cryptographic\n * functions to use for the client.\n * @returns The method implementation which returns a `JsonSLIP10Node`.\n * @throws If the params are invalid.\n */\nexport function getBip32EntropyImplementation({\n methodHooks: { getUnlockPromise, getClientCryptography },\n messenger,\n}: GetBip32EntropySpecificationBuilderOptions) {\n return async function getBip32Entropy(\n args: RestrictedMethodOptions<GetBip32EntropyParams>,\n ): Promise<GetBip32EntropyResult> {\n await getUnlockPromise(true);\n\n const { params } = args;\n assert(params);\n\n // Using the seed is much faster, but we can only do it for these specific curves.\n if (params.curve === 'secp256k1' || params.curve === 'ed25519') {\n const seed = await getValueFromEntropySource(\n getMnemonicSeed.bind(null, messenger),\n params.source,\n );\n\n const node = await getNodeFromSeed({\n curve: params.curve,\n path: params.path,\n seed,\n cryptographicFunctions: getClientCryptography(),\n });\n\n return node.toJSON();\n }\n\n const secretRecoveryPhrase = await getValueFromEntropySource(\n getMnemonic.bind(null, messenger),\n params.source,\n );\n\n const node = await getNodeFromMnemonic({\n curve: params.curve,\n path: params.path,\n secretRecoveryPhrase,\n cryptographicFunctions: getClientCryptography(),\n });\n\n return node.toJSON();\n };\n}\n"]}