Today we're going to build a simple React / Web3 Dapp that replicates a small portion of the Uniswap v2 interface - specifically, we are building the "account login" button that allows users to connect to a Dapp using their MetaMask extension.
By the end of the tutorial you will have a working React app that will be able to connect to your MetaMask account, and read your address & ETH balance. If you connect with multiple accounts the interface will change to reflect the active account.
A lot of tutorials skip this basic login strategy, or use outdated libraries (which you don't find out until you're halfway through!). To avoid confusion, as of July, 2021 this tutorial & the accompanying repo uses the following tech:
MetaMask is a mobile wallet that provides easy access to websites that use the Ethereum blockchain.
For up to the minute news, follow our Twitter or Medium pages.
To learn how to develop MetaMask-compatible applications, visit our Developer Docs.
%%{ init: { 'flowchart': { 'curve': 'bumpX' } } }%%
graph LR;
linkStyle default opacity:0.5
address_book_controller(["@metamask/address-book-controller"]);
announcement_controller(["@metamask/announcement-controller"]);
approval_controller(["@metamask/approval-controller"]);
assets_controllers(["@metamask/assets-controllers"]);
base_controller(["@metamask/base-controller"]);
composable_controller(["@metamask/composable-controller"]);
controller_utils(["@metamask/controller-utils"]);
ens_controller(["@metamask/ens-controller"]);
gas_fee_controller(["@metamask/gas-fee-controller"]);
keyring_controller(["@metamask/keyring-controller"]);
logging_controller(["@metamask/logging-controller"]);
message_manager(["@metamask/message-manager"]);
name_controller(["@metamask/name-controller"]);
network_controller(["@metamask/network-controller"]);
notification_controller(["@metamask/notification-controller"]);
permission_controller(["@metamask/permission-controller"]);
phishing_controller(["@metamask/phishing-controller"]);
preferences_controller(["@metamask/preferences-controller"]);
rate_limit_controller(["@metamask/rate-limit-controller"]);
signature_controller(["@metamask/signature-controller"]);
transaction_controller(["@metamask/transaction-controller"]);
address_book_controller --> base_controller;
address_book_controller --> controller_utils;
announcement_controller --> base_controller;
approval_controller --> base_controller;
assets_controllers --> approval_controller;
assets_controllers --> base_controller;
assets_controllers --> controller_utils;
assets_controllers --> network_controller;
assets_controllers --> preferences_controller;
composable_controller --> base_controller;
ens_controller --> base_controller;
ens_controller --> controller_utils;
ens_controller --> network_controller;
gas_fee_controller --> base_controller;
gas_fee_controller --> controller_utils;
gas_fee_controller --> network_controller;
keyring_controller --> base_controller;
keyring_controller --> message_manager;
keyring_controller --> preferences_controller;
logging_controller --> base_controller;
logging_controller --> controller_utils;
message_manager --> base_controller;
message_manager --> controller_utils;
name_controller --> base_controller;
network_controller --> base_controller;
network_controller --> controller_utils;
notification_controller --> base_controller;
permission_controller --> approval_controller;
permission_controller --> base_controller;
permission_controller --> controller_utils;
phishing_controller --> base_controller;
phishing_controller --> controller_utils;
preferences_controller --> base_controller;
preferences_controller --> controller_utils;
rate_limit_controller --> base_controller;
signature_controller --> approval_controller;
signature_controller --> base_controller;
signature_controller --> controller_utils;
signature_controller --> message_manager;
transaction_controller --> approval_controller;
transaction_controller --> base_controller;
transaction_controller --> controller_utils;
transaction_controller --> network_controller;
There are 2 packages in this repo: a backend
which is a REST API written in Express, and a frontend
which is a React single-page application. It's really a demo, so I tried to use as few libraries as possible, and the most popular ones when possible.
The simplest way to get started is to launch the demo using Docker Compose. Alternatively you could launch docker the containers manually, or run the node services using yarn.
docker-compose up -d
This will setup the bakcend listening on localhost:8000
and the frontend on localhost:3000
.
Build and launch the backend:
cd backend
docker build -t login-backend .
docker run -d -p 8000:8000 login-backend
Whenever you change dependencies (adding, removing, or updating, either in package.json
or yarn.lock
), there are various files that must be kept up-to-date.
yarn.lock
:- Run
yarn setup
again after your changes to ensureyarn.lock
has been properly updated.
- Run
- The
allow-scripts
configuration inpackage.json
- Run
yarn allow-scripts auto
to update theallow-scripts
configuration automatically. This config determines whether the package's install/postinstall scripts are allowed to run. Review each new package to determine whether the install script needs to run or not, testing if necessary. - Unfortunately,
yarn allow-scripts auto
will behave inconsistently on different platforms. macOS and Windows users may see extraneous changes relating to optional dependencies.
- Run
Contributions are welcome, but please follow these contributor guidelines outlined in CONTRIBUTING.md.
metamask is licensed under a BSD 2-Clause License and is copyright Intoli, LLC.