React Native has established itself as one of the leading frameworks for hybrid mobile development. According to statista.com the global average of mobile users is currently at 70% with mobile devices accounting for about half of web page views. Mobile apps are becoming (if not already) the means for us connecting with each other across the world, and thus this has serious implications for how we conduct our finance. Special thanks to fmsouza developing a scaffold for this implementation.
Ethereum is a global, open-source platform for decentralized applications. On Ethereum, we can write code that controls digital value and essentially program our money. So let's jump right into it. 🚀
We are going to build React Native dApp that can
Create an Ethereum wallet for a user
Receive Ether/value by this wallet
Send Ether to another wallet
View our total balance amongst our wallets in both Ether and FIAT currency
For reference here's the repo:
I am currently in the process of upgrading a number of packages that are old in this project, as well as migrating to React Hooks but in the interim, this should get people started. I will write a separate article with the refactored code.
I'll be using
react-native init to create this project. I am using React Native version
0.59.9, because there have been issues integrating with React Native 0.6+. I will address those in a separate article. Run the following command
this will, of course, add all the necessary dependencies to create a basic functioning react native app.
I'll be using a variety of different packages to build this app, in particular:
react-navigation to navigate around the app
react-native-camera to scan QR Codes for adding wallets easily.
mobx for state management
axios for our http calls
I will utilize other dependencies and dev dependencies which I will mention at particular snippets, but for the purposes of this article, I chose to highlight the main packages.
So if you have any familiarity with redux then you may already understand what a store is, for those of of you who don't, The main responsibility of stores is to move logic and state out of your components into a standalone testable unit. You can read more here
we use the
@action decorator on any action that is going to modify an observable . Here we a variety of functions related to the manipulation of a particular instance of wallet's state. Here we deal with pending transactions, updating wallet history and reseting our stores.
These make specific modifications on our state but are not directly called from components, which just adds another layer of modularization and follows general Flux architecture. Our Actions will be responsible for this.
This store is responsible for dealing with our conversion to FIAT, here we set the various conversion rates that we would like to display to the user.
These interact with our external providers, such as ethers.js or any http requests (to get our crypto rates or blockchain transactions), using axios , as well as persistent storage (for storing our private 🔑 .
we get our prices and blockchain transactions from our api.js service, our
getPrice gets the FIAT rates returned as a json object.
Here's another example where we actually send the ether to another address.
So these files wrap it all together, and are slightly distinguished from typical actions in a flux architecture in that these are responsible for changing state, calling services (which are more than likely asynchronous) and returning the result. They are called directly from components and I think it allows for more testable units when they are segregated in this way.
Here's an example of how our transactions actions file. Here we handle sending ether to another wallet. As you can see we make calls to the
@actions that we defined in our stores whilst making calls to our services such as
TransactionsService which handles the actual sending of the ether from Address A to Address B using ethers.js as well as some other error handling. After we send that ether, we want to update our wallet to reflect that transaction in our history, and the wait for it to be confirmed i.e. for a Transaction receipt once the transactionHash has been mined, then notify our user that is has been confirmed.
Here's an example now, of how this type of modularity makes testing easy
I can call send a ether essentially from loading a wallet, creating a transaction and then awaiting it to be confirmed, and if I have issues I know that I won't have to debug my
createTransaction function, nor the instantiation of a wallet.
So as you can tell from the
package.json I used
NativeBase components to make life a bit easier, rather than completely solely custom components. On the home page, we want to load the wallets a user may have, but if they have not created any, then we want to prompt them to do so. We use a
FlatList to list the existing wallets and our
NoWallet component handles the initial step of the Wallet creation process.
ComponentDidMount we call the
populate function which dispatches the
getPrice functions, that will load the wallets and display their total unspent outputs or 'value' in FIAT.