diff --git a/packages/examples/README.md b/packages/examples/README.md index 35071f469b..29c4725ed1 100644 --- a/packages/examples/README.md +++ b/packages/examples/README.md @@ -31,7 +31,8 @@ The following is a list of the snaps in this directory. - [**`packages/ethereum-provider`**](./packages/ethereum-provider): This snap demonstrates how to use the `endowment:ethereum-provider` permission and corresponding `ethereum` provider to interact with the Ethereum blockchain - from a snap. + from a snap. This also demonstrates how a snap can access a user's existing + Ethereum accounts. - [**`packages/invoke-snap`**](./packages/invoke-snap): These snaps demonstrate how to use the `snap_invokeSnap` method to invoke another snap. - [**`packages/json-rpc`**](./packages/json-rpc): This snap demonstrates how to diff --git a/packages/examples/packages/ethereum-provider/README.md b/packages/examples/packages/ethereum-provider/README.md index 9546a6539c..60eb40fd89 100644 --- a/packages/examples/packages/ethereum-provider/README.md +++ b/packages/examples/packages/ethereum-provider/README.md @@ -31,6 +31,8 @@ JSON-RPC methods: - `getGasPrice`: Get the current recommended gas price from an Ethereum provider. - `getVersion`: Get the Ethereum network version from an Ethereum provider. +- `getAccounts`: Get the Ethereum accounts made available to the snap from an + Ethereum provider. For more information, you can refer to [the end-to-end tests](./src/index.test.ts). diff --git a/packages/examples/packages/ethereum-provider/snap.manifest.json b/packages/examples/packages/ethereum-provider/snap.manifest.json index 169140638d..9c176e9d82 100644 --- a/packages/examples/packages/ethereum-provider/snap.manifest.json +++ b/packages/examples/packages/ethereum-provider/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/snaps.git" }, "source": { - "shasum": "8x3fuQFIBQPIdn6lNSnNMlLyX86WHtz1RfXepxvdi9Q=", + "shasum": "pk/dhRK6jR/Z4mXOZVgPk+2HP0keUmZu3873goarGMI=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/examples/packages/ethereum-provider/src/index.ts b/packages/examples/packages/ethereum-provider/src/index.ts index f33ee6146f..e514699749 100644 --- a/packages/examples/packages/ethereum-provider/src/index.ts +++ b/packages/examples/packages/ethereum-provider/src/index.ts @@ -3,8 +3,8 @@ import { OnRpcRequestHandler } from '@metamask/snaps-types'; import { assert, Hex } from '@metamask/utils'; /** - * Get the current gas price using the `ethereum` global. This essentially the - * same as the `window.ethereum` global, but does not have access to all + * Get the current gas price using the `ethereum` global. This is essentially + * the same as the `window.ethereum` global, but does not have access to all * methods. * * Note that using the `ethereum` global requires the @@ -21,9 +21,9 @@ async function getGasPrice() { } /** - * Get the current network version using the `ethereum` global. This essentially - * the same as the `window.ethereum` global, but does not have access to all - * methods. + * Get the current network version using the `ethereum` global. This is + * essentially the same as the `window.ethereum` global, but does not have + * access to all methods. * * Note that using the `ethereum` global requires the * `endowment:ethereum-provider` permission. @@ -38,12 +38,38 @@ async function getVersion() { return version; } +/** + * Get the Ethereum accounts that the snap has access to using the `ethereum` + * global. This is essentially the same as the `window.ethereum` global, but + * does not have access to all methods. + * + * If the user hasn't given the snap access to any accounts yet, this JSON-RPC + * method will show a prompt to the user, asking them to select the accounts to + * give the snap access to. + * + * Note that using the `ethereum` global requires the + * `endowment:ethereum-provider` permission. + * + * @returns The selected accounts as an array of hexadecimal strings. + * @throws If the user rejects the prompt. + * @see https://docs.metamask.io/snaps/reference/permissions/#endowmentethereum-provider + */ +async function getAccounts() { + const accounts = await ethereum.request({ + method: 'eth_requestAccounts', + }); + assert(accounts, 'Ethereum provider did not return accounts.'); + + return accounts; +} + /** * Handle incoming JSON-RPC requests from the dapp, sent through the - * `wallet_invokeSnap` method. This handler handles two methods: + * `wallet_invokeSnap` method. This handler handles three methods: * * - `getGasPrice`: Get the current Ethereum gas price as a hexadecimal string. * - `getVersion`: Get the current Ethereum network version as a string. + * - `getAccounts`: Get the Ethereum accounts that the snap has access to. * * @param params - The request parameters. * @param params.request - The JSON-RPC request object. @@ -59,6 +85,9 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => { case 'getVersion': return await getVersion(); + case 'getAccounts': + return await getAccounts(); + default: throw rpcErrors.methodNotFound({ data: { diff --git a/packages/test-snaps/src/features/snaps/ethereum-provider/EthereumProvider.tsx b/packages/test-snaps/src/features/snaps/ethereum-provider/EthereumProvider.tsx index 2a403de5ae..4947b8bd98 100644 --- a/packages/test-snaps/src/features/snaps/ethereum-provider/EthereumProvider.tsx +++ b/packages/test-snaps/src/features/snaps/ethereum-provider/EthereumProvider.tsx @@ -1,6 +1,6 @@ import { logError } from '@metamask/snaps-utils'; import { FunctionComponent } from 'react'; -import { Button } from 'react-bootstrap'; +import { Button, ButtonGroup } from 'react-bootstrap'; import { useInvokeMutation } from '../../../api'; import { Result, Snap } from '../../../components'; @@ -13,13 +13,16 @@ import { export const EthereumProvider: FunctionComponent = () => { const [invokeSnap, { isLoading, data, error }] = useInvokeMutation(); - const handleSubmit = () => { + const handleSubmit = (method: string) => { invokeSnap({ snapId: getSnapId(ETHEREUM_PROVIDER_SNAP_ID, ETHEREUM_PROVIDER_SNAP_PORT), - method: 'getVersion', + method, }).catch(logError); }; + const handleGetVersion = () => handleSubmit('getVersion'); + const handleGetAccounts = () => handleSubmit('getAccounts'); + return ( { port={ETHEREUM_PROVIDER_SNAP_PORT} testId="ethereum-provider" > - + + + + {JSON.stringify(data, null, 2)}