Ethereum and Angular — Part 1
Create a Decentralized Application (Dapp)
Let’s interact with Ethereum through an Angular application.
Setup
A decentralized application, or Dapp, is a client application that interacts with the Ethereum blockchain.
Create an Angular application with angular-cli
ng new ng-eth
Once all the dependencies are installed, we will add the JavaScript library Web3. js which allow us to interact with the Ethereum blockchain. Note that Web3 is in development and version 1.0.0 is still in beta.
npm install web3@1.0.0-beta.30
Let’s start by creating a new module for this application: `ethereum`. The purpose of this module is to bring together all the components and services to interact with the Ethereum blockchain.
ng g module ethereum
The module will consist of several components often used on decentralized applications as well as a set of services that will handle blockchain data.
Instanciate Web3
The Web3 library provides us with a class that we need to instantiate and that will be reused in several services of the application. The best way to reuse the same instance of a class in several Angular classes is to create an InjectionToken
with useFactory
:
In the Ethereum
folder newly created by angular-cli add a new file: tokens. ts
Ethereum
ethereum.module.ts
tokens.ts
Let’s create a WEB3 token:
This code allows us to define a Token that we can inject into Angular classes. To do this, add a provider to the list of providers of ethereum. module. ts
.
First, import Web3. The file of definitions of Typescript types not yet updated I would recommend you to use require
.
const Web3 = require(‘web3’) ;
Then add WEB3 as the module provider:
providers: [{
provide: WEB3,
useFactory: () => new Web3(Web3.givenProvider || "ws://localhost:8546");
}]
We are adding a new provider to the ethereum module that inject web3 throughout the module, and other modules that will import EthereumModule
. Notice here that we use useFactory
to create a single instance of our Web3 class across the entire application.
Let’s focus a little on Web3 content:
The code new Web3 (Web3. givenProvider || “ws: //localhost: 8546”);
comes directly from the documentation of Web3. To interact with the Ethereum blockchain, a decentralized application must first connect to a node in the network. There are two options for this:
- Either your user opens your application in an environment that is already connected to a node (MetaMask, Mist, Toshi,…) in this case we use the
Web3. givenProvider
. - Either your user has a node running on his machine and in this case he connects to that node. Note that the protocol recommended by web3 to connect to a node is the WebSocket:
ws: //localhost: 8546
.
Note that it is also possible to manage your own provider with the metamask provider-engine, but this will be the subject of another article.
Let’s emphasize the need to use the Web3. givenProvider
. If your user opens your dapp in a specific environment he is likely to expect your dapp to open this specific environment graphic interface when he interact with the blockchain (signing a transaction or a message). If it does not find these interfaces it will not trust your DAPP.
Our module should look like this:
Interact with the blockchain
So we instantiated the Web3 class with the environment best suited to each user, it’s time to use it in a service to interact with the blockchain.
Let’s create a service in our ethereum module: eth
ng g service Ethereum/eth
Start by injecting our instance of web3 :
constructor(@Inject(WEB3) private web3: Web3) { }
Here we use the @Inject decorator to retrieve the value of the Token added to the module’s list of providers.
The purpose of this service is to encapsulate the Web3 functions of the Eth module. Web3 is built to be asynchronous and each asynchronous function returns a Promise. Angular making rather an intensive use of Observables, we can encapsulate some of these Promises in Observables to simplify integration with the rest of the application.
Let’s just start by retrieving the list of available accounts on the node
For the moment this function only encapsulates the web3 function in an observable one. Now let’s create a feature to access the selected account or the first account if no account is selected.
This function makes full use of the power of observables. Let’s cut it into pieces:
if (this.web3.eth.defaultAccount) {
return of(this.web3.eth.defaultAccount);
}
We first check if there is already a selected account on our web3 instance. If yes we return an observable with the address of this account. The use of an observable here allows the function to behave in the same way regardless of the result of the condition.
else {
...
}
If no account is selected, we use the previous function to retrieve the list of available accounts. This function returns an ethereum address array encapsulated in an observable. We first check that the table is not empty, otherwise we return an error that will then be retrieved in the catchError
.
If the table is not empty, we get the first address and use it to define this address as the one of the account selected in the web3 instance. This will prevent us from searching the list of available accounts later on.
Remember that all these operators must be imported into the file in order to be used:
We now have the necessary functions to interact with the blockchain. In the next article we will implement this service in a component.