Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/examples/packages/bip32/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ JSON-RPC methods:
(ECDSA for `secp256k1` and EdDSA for `ed25519`).

For more information, you can refer to
[the end-to-end tests](./src/index.test.ts).
[the end-to-end tests](./src/index.test.tsx).
2 changes: 1 addition & 1 deletion packages/examples/packages/bip32/snap.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { SnapConfig } from '@metamask/snaps-cli';
import { resolve } from 'path';

const config: SnapConfig = {
input: resolve(__dirname, 'src/index.ts'),
input: resolve(__dirname, 'src/index.tsx'),
server: {
port: 8001,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/bip32/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "dzOD3mPn8PgVXC3LT3OtKqs09WIcvuYo/mIZGfhsTPw=",
"shasum": "Yv3r9ZD/tEehqvSUa/EfcAKa61eYLNvhqtRXxYy++q4=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from '@jest/globals';
import { assertIsConfirmationDialog, installSnap } from '@metamask/snaps-jest';
import { copyable, heading, panel, text } from '@metamask/snaps-sdk';
import { Box, Copyable, Heading, Text } from '@metamask/snaps-sdk/jsx';

describe('onRpcRequest', () => {
it('throws an error if the requested method does not exist', async () => {
Expand Down Expand Up @@ -38,6 +38,23 @@ describe('onRpcRequest', () => {
);
});

it('returns an secp256k1 public key for a given BIP-32 path with a different source', async () => {
const { request } = await installSnap();

const response = await request({
method: 'getPublicKey',
params: {
path: ['m', "44'", "0'"],
curve: 'secp256k1',
source: 'alternative',
},
});

expect(response).toRespondWith(
'0x04f72f0e3684b0d7295f391616f12a469070bfcd175c55366239047495a2c1c410b4d820fb4147de213a2d25fb19f9451354ad5949fc881a2d219529703416de73',
);
});

it('returns a compressed secp256k1 public key for a given BIP-32 path', async () => {
const { request } = await installSnap();

Expand Down Expand Up @@ -110,15 +127,14 @@ describe('onRpcRequest', () => {
const ui = await response.getInterface();
assertIsConfirmationDialog(ui);
expect(ui).toRender(
panel([
heading('Signature request'),
text(
`Do you want to secp256k1 sign "Hello, world!" with the following public key?`,
),
copyable(
'0x0423a6a6f8800b2d0710595969f40148a28953c9eebc0c0da78a89be3b3935f59c0069dfe1cace1a083e9c962c9f2ef932e9346cd907e647d993d787c4e59d03d1',
),
]),
<Box>
<Heading>Signature request</Heading>
<Text>
Do you want to {'secp256k1'} sign "{'Hello, world!'}" with the
following public key?
</Text>
<Copyable value="0x0423a6a6f8800b2d0710595969f40148a28953c9eebc0c0da78a89be3b3935f59c0069dfe1cace1a083e9c962c9f2ef932e9346cd907e647d993d787c4e59d03d1" />
</Box>,
);

await ui.ok();
Expand All @@ -128,6 +144,39 @@ describe('onRpcRequest', () => {
);
});

it('signs a message for the given BIP-32 path using secp256k1 with a different source', async () => {
const { request } = await installSnap();

const response = request({
method: 'signMessage',
params: {
path: ['m', "44'", "0'"],
curve: 'secp256k1',
message: 'Hello, world!',
source: 'alternative',
},
});

const ui = await response.getInterface();
assertIsConfirmationDialog(ui);
expect(ui).toRender(
<Box>
<Heading>Signature request</Heading>
<Text>
Do you want to {'secp256k1'} sign "{'Hello, world!'}" with the
following public key?
</Text>
<Copyable value="0x04f72f0e3684b0d7295f391616f12a469070bfcd175c55366239047495a2c1c410b4d820fb4147de213a2d25fb19f9451354ad5949fc881a2d219529703416de73" />
</Box>,
);

await ui.ok();

expect(await response).toRespondWith(
'0x3044022049a3e74ed526df8b2a8e16e95a181d909255c90f6f63eb8efc16625af917b07d022014f2b203b0749058cbfc3ad0456c7b2bdf1ab809fd5913c6ee272cfc56f30ef2',
);
});

it('signs a message for the given BIP-32 path using ed25519', async () => {
const { request } = await installSnap();

Expand All @@ -143,15 +192,14 @@ describe('onRpcRequest', () => {
const ui = await response.getInterface();
assertIsConfirmationDialog(ui);
expect(ui).toRender(
panel([
heading('Signature request'),
text(
`Do you want to ed25519 sign "Hello, world!" with the following public key?`,
),
copyable(
'0x000b96ba23cae9597de51e0187d7ef1b2d1a782dc2d5ceac770a327de3844dd533',
),
]),
<Box>
<Heading>Signature request</Heading>
<Text>
Do you want to {'ed25519'} sign "{'Hello, world!'}" with the
following public key?
</Text>
<Copyable value="0x000b96ba23cae9597de51e0187d7ef1b2d1a782dc2d5ceac770a327de3844dd533" />
</Box>,
);

await ui.ok();
Expand All @@ -176,15 +224,14 @@ describe('onRpcRequest', () => {
const ui = await response.getInterface();
assertIsConfirmationDialog(ui);
expect(ui).toRender(
panel([
heading('Signature request'),
text(
`Do you want to ed25519Bip32 sign "Hello, world!" with the following public key?`,
),
copyable(
'0x2c3ac523b470dead7981df46c93d894ed4381e94c23aa1ec3806a320ff8ceb42',
),
]),
<Box>
<Heading>Signature request</Heading>
<Text>
Do you want to {'ed25519Bip32'} sign "{'Hello, world!'}" with the
following public key?
</Text>
<Copyable value="0x2c3ac523b470dead7981df46c93d894ed4381e94c23aa1ec3806a320ff8ceb42" />
</Box>,
);

await ui.ok();
Expand Down Expand Up @@ -217,4 +264,29 @@ describe('onRpcRequest', () => {
});
});
});

describe('getEntropySources', () => {
it('returns the entropy sources', async () => {
const { request } = await installSnap();

const response = request({
method: 'getEntropySources',
});

expect(await response).toRespondWith([
{
id: 'default',
name: 'Default Secret Recovery Phrase',
type: 'mnemonic',
primary: true,
},
{
id: 'alternative',
name: 'Alternative Secret Recovery Phrase',
type: 'mnemonic',
primary: false,
},
]);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import type { OnRpcRequestHandler } from '@metamask/snaps-sdk';
import {
DialogType,
panel,
text,
heading,
copyable,
InvalidParamsError,
UserRejectedRequestError,
MethodNotFoundError,
} from '@metamask/snaps-sdk';
import { Box, Copyable, Heading, Text } from '@metamask/snaps-sdk/jsx';
import {
add0x,
assert,
Expand All @@ -30,6 +27,7 @@ import { getPrivateNode, getPublicKey } from './utils';
* key is returned in hex format.
* - `signMessage`: Derive a BIP-32 private key for a given BIP-32 path, and use
* it to sign a message. The signature is returned in hex format.
* - `getEntropySources`: Get the list of entropy sources available to the Snap.
*
* @param params - The request parameters.
* @param params.request - The JSON-RPC request object.
Expand Down Expand Up @@ -62,13 +60,16 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => {
method: 'snap_dialog',
params: {
type: DialogType.Confirmation,
content: panel([
heading('Signature request'),
text(
`Do you want to ${curve} sign "${message}" with the following public key?`,
),
copyable(add0x(node.publicKey)),
]),
content: (
<Box>
<Heading>Signature request</Heading>
<Text>
Do you want to {curve} sign "{message}" with the following
public key?
</Text>
<Copyable value={add0x(node.publicKey)} />
</Box>
),
},
});

Expand Down Expand Up @@ -97,6 +98,12 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => {
throw new Error(`Unsupported curve: ${String(curve)}.`);
}

case 'getEntropySources': {
return await snap.request({
method: 'snap_listEntropySources',
});
}

default:
throw new MethodNotFoundError({ method: request.method });
}
Expand Down
12 changes: 12 additions & 0 deletions packages/examples/packages/bip32/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ export type GetBip32PublicKeyParams = {
*/
compressed?: boolean | undefined;

/**
* The entropy source to use for the signature. If not provided, the primary
* entropy source will be used.
*/
source?: string | undefined;

/**
* Miscellaneous parameters, which are passed to `snap_getBip32PublicKey`.
*/
Expand Down Expand Up @@ -47,4 +53,10 @@ export type SignMessageParams = {
* The curve used to derive the account.
*/
curve: 'secp256k1' | 'ed25519' | 'ed25519Bip32';

/**
* The entropy source to use for the signature. If not provided, the primary
* entropy source will be used.
*/
source?: string | undefined;
};
2 changes: 1 addition & 1 deletion packages/examples/packages/bip44/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,4 @@ JSON-RPC methods:
elliptic curve to sign the message.

For more information, you can refer to
[the end-to-end tests](./src/index.test.ts).
[the end-to-end tests](./src/index.test.tsx).
2 changes: 1 addition & 1 deletion packages/examples/packages/bip44/snap.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { SnapConfig } from '@metamask/snaps-cli';
import { resolve } from 'path';

const config: SnapConfig = {
input: resolve(__dirname, 'src/index.ts'),
input: resolve(__dirname, 'src/index.tsx'),
server: {
port: 8002,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/examples/packages/bip44/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/snaps.git"
},
"source": {
"shasum": "t0+OXVvAOnJOEgxjLB9Gz9CtAhNJr0nj9WC7nEeEZUs=",
"shasum": "s8y7K5HyKWgxVflPhs/Tdt69c/L2QT/vixntD9dnu+o=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
Loading
Loading