Skip to content

Commit

Permalink
Add eth_requestAccounts usage to the Ethereum provider example (#1579)
Browse files Browse the repository at this point in the history
* Add eth_requestAccounts to the Ethereum provider example

* Update docs

* Fix some spacing issues

* One more spacing issue

---------

Co-authored-by: Maarten Zuidhoorn <maarten@zuidhoorn.com>
  • Loading branch information
FrederikBolding and Mrtenz authored Jul 11, 2023
1 parent bd7b914 commit c2243f0
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 20 deletions.
3 changes: 2 additions & 1 deletion packages/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions packages/examples/packages/ethereum-provider/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
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": "8x3fuQFIBQPIdn6lNSnNMlLyX86WHtz1RfXepxvdi9Q=",
"shasum": "pk/dhRK6jR/Z4mXOZVgPk+2HP0keUmZu3873goarGMI=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
41 changes: 35 additions & 6 deletions packages/examples/packages/ethereum-provider/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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<string[]>({
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.
Expand All @@ -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: {
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -13,29 +13,43 @@ 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 (
<Snap
name="Ethereum Provider Snap"
snapId={ETHEREUM_PROVIDER_SNAP_ID}
port={ETHEREUM_PROVIDER_SNAP_PORT}
testId="ethereum-provider"
>
<Button
variant="primary"
id="sendEthprovider"
className="mb-3"
disabled={isLoading}
onClick={handleSubmit}
>
Get Version
</Button>
<ButtonGroup>
<Button
variant="secondary"
id="sendEthprovider"
className="mb-3"
disabled={isLoading}
onClick={handleGetVersion}
>
Get Version
</Button>
<Button
variant="primary"
id="sendEthproviderAccounts"
className="mb-3"
disabled={isLoading}
onClick={handleGetAccounts}
>
Get Accounts
</Button>
</ButtonGroup>
<Result>
<span id="ethproviderResult">
{JSON.stringify(data, null, 2)}
Expand Down

0 comments on commit c2243f0

Please sign in to comment.