@metamask/snaps-rpc-methods
Version:
MetaMask Snaps JSON-RPC method implementations
145 lines • 6.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBip32EntropyImplementation = exports.getBip32EntropyBuilder = void 0;
const permission_controller_1 = require("@metamask/permission-controller");
const rpc_errors_1 = require("@metamask/rpc-errors");
const snaps_utils_1 = require("@metamask/snaps-utils");
const utils_1 = require("@metamask/utils");
const utils_2 = require("../utils.cjs");
const targetName = 'snap_getBip32Entropy';
/**
* The specification builder for the `snap_getBip32Entropy` permission.
* `snap_getBip32Entropy` lets the Snap control private keys for a particular
* BIP-32 node.
*
* @param options - The specification builder options.
* @param options.messenger - The messenger.
* @param options.methodHooks - The RPC method hooks needed by the method implementation.
* @returns The specification for the `snap_getBip32Entropy` permission.
*/
const specificationBuilder = ({ methodHooks, messenger, }) => {
return {
permissionType: permission_controller_1.PermissionType.RestrictedMethod,
targetName,
allowedCaveats: [snaps_utils_1.SnapCaveatType.PermittedDerivationPaths],
methodImplementation: getBip32EntropyImplementation({
methodHooks,
messenger,
}),
validator: ({ caveats }) => {
if (caveats?.length !== 1 ||
caveats[0].type !== snaps_utils_1.SnapCaveatType.PermittedDerivationPaths) {
throw rpc_errors_1.rpcErrors.invalidParams({
message: `Expected a single "${snaps_utils_1.SnapCaveatType.PermittedDerivationPaths}" caveat.`,
});
}
},
subjectTypes: [permission_controller_1.SubjectType.Snap],
};
};
const methodHooks = {
getUnlockPromise: true,
getClientCryptography: true,
};
/**
* Enables you to [manage users' non-EVM accounts](https://docs.metamask.io/snaps/features/non-evm-networks/)
* by deriving the [SLIP-10](https://github.com/satoshilabs/slips/blob/master/slip-0010.md)
* keys specified by the `path` and `curve` parameters. The keys are derived
* using the entropy from the user's Secret Recovery Phrase.
*
* If the keys you want to derive conform to the [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
* structure, use [snap_getBip44Entropy](https://docs.metamask.io/snaps/reference/snaps-api/snap_getbip44entropy)
* instead. Otherwise, use this method.
*
* This method is designed to be used with the [`@metamask/key-tree`](https://npmjs.com/package/@metamask/key-tree)
* module. `@metamask/key-tree` can help you get the [extended private keys](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#extended-keys)
* for user addresses, but it's your responsibility to know how to use those
* keys to, for example, derive an address for the relevant protocol or sign a
* transaction for the user.
*
* @example
* ```json name="Manifest"
* {
* "initialPermissions": {
* "snap_getBip32Entropy": [
* {
* "path": ["m", "44'", "3'"],
* "curve": "secp256k1" // Or "ed25519", "ed25519Bip32"
* }
* ]
* }
* }
* ```
* ```ts name="Usage"
* import { SLIP10Node } from '@metamask/key-tree'
*
* // This example uses Dogecoin, which has a derivation path starting with
* // m/44'/3'.
* const dogecoinNode = await snap.request({
* method: 'snap_getBip32Entropy',
* params: {
* // The path and curve must be specified in the initial permissions.
* path: ['m', "44'", "3'"],
* curve: 'secp256k1',
* },
* })
*
* // Next, create an instance of a SLIP-10 node for the Dogecoin node.
* const dogecoinSlip10Node = await SLIP10Node.fromJSON(dogecoinNode)
*
* // m/44'/3'/0'
* const accountKey0 = await dogecoinSlip10Node.derive(["bip32:0'"])
*
* // m/44'/3'/1'
* const accountKey1 = await dogecoinSlip10Node.derive(["bip32:1'"])
*
* // Now, you can ask the user to sign transactions, etc.
* ```
*/
exports.getBip32EntropyBuilder = Object.freeze({
targetName,
specificationBuilder,
methodHooks,
actionNames: ['KeyringController:withKeyringV2Unsafe'],
});
/**
* Builds the method implementation for `snap_getBip32Entropy`.
*
* @param options - The options.
* @param options.messenger - The messenger.
* @param options.methodHooks - The RPC method hooks.
* @param options.methodHooks.getUnlockPromise - A function that resolves once the MetaMask extension is unlocked
* and prompts the user to unlock their MetaMask if it is locked.
* @param options.methodHooks.getClientCryptography - A function to retrieve the cryptographic
* functions to use for the client.
* @returns The method implementation which returns a `JsonSLIP10Node`.
* @throws If the params are invalid.
*/
function getBip32EntropyImplementation({ methodHooks: { getUnlockPromise, getClientCryptography }, messenger, }) {
return async function getBip32Entropy(args) {
await getUnlockPromise(true);
const { params } = args;
(0, utils_1.assert)(params);
// Using the seed is much faster, but we can only do it for these specific curves.
if (params.curve === 'secp256k1' || params.curve === 'ed25519') {
const seed = await (0, utils_2.getValueFromEntropySource)(utils_2.getMnemonicSeed.bind(null, messenger), params.source);
const node = await (0, utils_2.getNodeFromSeed)({
curve: params.curve,
path: params.path,
seed,
cryptographicFunctions: getClientCryptography(),
});
return node.toJSON();
}
const secretRecoveryPhrase = await (0, utils_2.getValueFromEntropySource)(utils_2.getMnemonic.bind(null, messenger), params.source);
const node = await (0, utils_2.getNodeFromMnemonic)({
curve: params.curve,
path: params.path,
secretRecoveryPhrase,
cryptographicFunctions: getClientCryptography(),
});
return node.toJSON();
};
}
exports.getBip32EntropyImplementation = getBip32EntropyImplementation;
//# sourceMappingURL=getBip32Entropy.cjs.map