There are a lot of good reasons to have a standalone native mobile app for your ethereum token/smart contract/DApp (Decentralized App):
But as you start thinking about building mobile apps, you will find yourself immediately confronted with some critical challenges:
These are real problems with no clear answers, with few people willing to talk about them. It occurred to me that one solution may be to rethink what an “app” is. To that end I tried to create a dead simple framework to bring us closer to that realization.
I started by building a simple ERC20 token mobile app that looks like this:
Throughout the rest of this article, I will discuss:
While I use specific tools and frameworks throughout this post, the general principle and the lesson should be applicable for anyone who’s thinking about building mobile apps on Ethereum.
Before getting to the mobile app, let’s take a look at all the ingredients we need to build the full stack:
Solidity Smart Contract
Since this post is not a tutorial about how to write smart contracts, I will just share a simple ERC20 token contract I deployed to Rinkeby (an Ethereum testnet).
You can find it in production here (remember to connect to Rinkeby): https://gliechtenstein.github.io/erc20/web/
And the source is here: https://github.com/gliechtenstein/erc20/tree/master/contracts
The code itself is 99% copy and pasted from OpenZeppelin contracts for simplicity and 1% customized.
The cool thing about standards like ERC for Ethereum is you can write once and use it everywhere, so most developers don’t have to worry about coming up with their own secure implementation, they can just reuse most of it and customize only what they need to. The entire community shares the benefits.
This is very in line with what I am trying to achieve with the solution I’m about to discuss in this article. The difference is Zeppelin and friends are focused on the backend (smart contract) and I am focused on the frontend (mobile app).
Web3.js DApp
I wrote a simple web3.js Dapp for dealing with the ERC20 token I deployed in the previous section.
For simplicity, I didn’t use complex tools and frameworks like Truffle, et al. It’s literally just a single flat HTML file. You can check out the code here: https://github.com/gliechtenstein/erc20/blob/master/web/index.html
INFURA : A Trusted Node, trusted by many, including MetaMask.
Most DApp developers nowadays acknowledge that it’s unrealistic to expect all users to download the entire blockchain which is hundreds of gigabytes. In fact, most users use a 3rd party trusted node instead. This is where the MetaMask desktop browser extension comes in.
MetaMask takes a “thin client” approach. Instead of downloading the full blockchain, it connects to a trusted node called Infura. Because of the public key cryptography that powers the whole blockchain — you sign each transaction with your local private key before broadcasting to the network so the network can’t forge it — it is generally considered safe enough to use trusted nodes just for broadcasting.
For mobile development, it makes even more sense to use trusted nodes like Infura because nobody wants to download tens of gigabytes of blockchain, waste network traffic and kill their battery from constant peer to peer synchronization. So let’s use Infura.
Infura - Scalable Blockchain Infrastructure_Secure, reliable, and scalable access to Ethereum APIs and IPFS gateways._infura.io
Jasonette: Cross-platform Native Mobile App Framework
The first building block is the native UI. We’ll use Jasonette, a markup driven approach to building cross-platform native apps.
Jasonette — Native App over HTTP_Jasonette turns JSON into iOS and Android native components._www.jasonette.com
Jasonette is like a web browser but for building native apps. Just like how web browsers interpret HTML on the fly and render it on the browser screen, Jasonette interprets a JSON markup to construct a native app on the fly on iOS and Android.
The markup syntax supports expression of everything from Model to View to Controller, so just a single JSON markup is all you need to build a native app.
Quick intro to how Jasonette works:
In-depth tutorial:
Agent: Microservice on the Mobile Frontend
One important built-in feature for Jasonette that’s critical for our use case is agent
.
An agent is like a microservice that you can embed in your native app frontend. It automatically forms a two way communication channel between the parent native app and itself, allowing them to communicate via a JSON-RPC protocol.
For example, you can take any web app that works in a browser, embed it in a native app as an agent, and instead of rendering some API data into the DOM, send it to the parent app as an event. Then the app can render it natively.
We will use agent to embed our existing web3 DApp into a native app and use it as a data source (and use the native part to render the data).
Take a quick look at the following page to learn more about agents:
Jasonette Agent_Turn any JavaScript app into a cross-platform native mobile app_www.jasonette.com
Now we’re ready to build the mobile app.
The above diagram is a quick overview of the overall data flow.
All of these are inter-connected through the JSON-RPC protocol, and the application — all three modules — is entirely described in JSON markup.
Before we jump in, just a reminder that you can find the entire source code at:
gliechtenstein/erc20_erc20 — Full stack ERC20 Token App (Contract + Web + Mobile)_github.com
With that said, now let’s take a look at each module.
The first building block is the native UI. Jasonette has a built-in templating engine — also written in JSON — that can take any JSON object and render into a native layout and UI components, as well as express native API function calls in JSON markup.
In this case we‘ll use the DApp container — which we’ll discuss in the next section — as data source, so we define the template and wait for a response from the DApp container. Once the DApp container triggers an event we’ll render the data against our template. Here’s the full markup:
https://github.com/gliechtenstein/erc20/blob/master/mobile/app/main.json
The cool thing about the markup driven approach is that the application logic is completely separated from the device. This means you can store and serve the app from anywhere (like how web browsers do it). It could be stored in a remote server, locally on the device, or even on decentralized storage like IPFS.
Let’s step back and think about what this means. By separating application from the device, we can make sure that regardless of whatever happens to Apple or Google in the future, our app will be portable to a new platform as long as the framework itself is ported to that new dominant platform. And this is why Jasonette chose JSON as the markup language, JSON is the most popular format for machines to store and communicate data with one another, therefore it is likely that the hypothetical “new platform” of the future will also support JSON as first class citizen.
For our MVP app, we serve it from a remote JSON hosted on github.
The second building block is the DApp container.
There are a couple of things to note from this diagram:
We instantiate the DApp container as an agent. Declaring an agent involves simply adding 3 lines of JSON to the existing app markup:
{"$jason": {"head": {"title": "Web3 DApp in a mobile app","agents": { "eth": {"url": "https://gliechtenstein.github.io/erc20/web_"}_ },... }}}
In this case we initialize the DApp container and name it eth
, which we will use as the ID when we make JSON-RPC calls.
Here’s the full source: https://github.com/gliechtenstein/erc20/blob/master/mobile/app/main.json
Note that we have not touched the original web app. We simply embedded our DAPP as an agent and are using it as an instant pseudo-backend for the mobile app. To be clear, you don’t have to do this and just keep a separate agent just for embedding into the mobile app, but I just wanted to show how you can reuse the same DApp for mobile.
Writing to Ethereum is trickier than reading. We must be more careful because it deals with creating actual transactions and sending real money.
Normally when building a regular DApp, we use the web3.js
library to make an API call like this:
contract.transfer.sendTransaction(receiver, tokens, {to: contract.address,gasLimit: 21000,gasPrice: 20000000000}, function(err, result) {// Render the DOM with result})
This method sendTransaction
actually does two things:
"transfer"
.For our project instead of having the DApp handle both, we will:
By separating the two, the DApp container doesn’t have to deal with private keys, but delegates it to the wallet container just like how MetaMask deals with this issue automatically on desktop. That way the DApp developer can focus on the application logic.
So instead of using the sendTransaction
method, we first use an API called getData
to get a transaction object:
var tx = contract.transfer.getData(receiver, tokens)
And then pass that back to the parent app through the [$agent.response](https://docs.jasonette.com/agents/#2-agentresponse)
API:
$agent.response({ tx: tx })
The parent native app then will pass it along to our new wallet view.
The wallet view (and the wallet agent it contains) will take this unsigned transaction data, sign it, and then broadcast it through Infura. You can check out the wallet view source code here: https://github.com/gliechtenstein/erc20/blob/master/mobile/wallet/wallet.json
Here’s the wallet agent code: https://github.com/gliechtenstein/erc20/blob/master/mobile/wallet/wallet.html
Note that the “wallet view” is a completely separate sandboxed view of its own, just like how MetaMask opens up in a new popup browser. This is by design. This insulates the DApp developer from ever having to deal with private keys.
To recap, here’s how our entire mobile app works:
What’s the benefit of building an app this way, especially for a decentralized network like Ethereum?
It’s simply much easier to build the app this way. You don’t have to rewrite your DApp to work on mobile, you don’t need to hire a mobile developer, you don’t need to maintain a separate mobile code base.
All you need to do is:
This gives you a single codebase that works both as your website and for mobile. The only thing you need to maintain is the markup. But even the markup — since it’s public — can be shared by different apps.
We can look at how the ERC standards for Ethereum work in order to understand the implication of this. Most ERC20 token developers simply inherit from Zeppelin’s zeppelin/solidity — the most audited and therefore most secure ERC20 token contract — and implement their own customization on top, which makes it much easier to build smart contracts while keeping it safe.
And I predict that same type of standards may emerge for building secure mobile frontends.
Every view is expressed as a single standalone JSON markup — just like all web pages are expressed as a single HTML markup — nothing hides behind complex dependencies that can make a piece of code hard to understand. None of the JSON markup syntax is device specific. Every view is standalone and sandboxed which also contributes to simplicity. Simplicity begets transparency.
To build a protocol that will last forever, you want your clients to be as transparent as possible, so a free market can form around clients for your protocol. This way your protocol can live on forever even after you move on from the project.
How To Write Code That Will Last Forever_And that's not because everyone is afraid to touch it_levelup.gitconnected.com
The example below uses exactly the same DApp we used above, but just with a different view markup to create a completely different interface.
I didn’t have to do anything fancy to make this change. What you see above is literally a single JSON markup which I forked from the earlier version. It took me less than 5 minutes to write:
https://github.com/gliechtenstein/erc20/blob/master/mobile/app/simple.json
What’s really cool about this is that YOU TOO can take the same markup and customize it for your own ERC20 token because all ERC20 tokens share the same backend protocol. Even the DApp container can be reused simply by switching out the contract address.
The mobile apps of tomorrow will be built on top of cryptographic protocols that connect to decentralized networks such as Bitcoin and Ethereum, instead of connecting to a centralized network like Facebook.
In this world, we may need to rethink the very notion of what a “mobile app” is, and how to build one without compromising a user’s security when their identity is baked into the protocol.
There is a concept called “The Rule of Least Power”, coined and implemented by Sir Tim Berners-Lee as the fundamental design principle for the World Wide Web.
The Rule of Least Power_The World Wide Web is unique in its ability to promote information reuse on a global scale. Information published on…_www.w3.org
The idea is that simple is superior to complex in a potentially dangerous environment, such as the Web. The rule states that a “descriptive” language is stronger than a “procedural” language:
“…given a choice among computer languages, … the less procedural, more descriptive the language one chooses, the more one can do with the data stored in that language.”
Also, a simple language is more secure than a complex one:
“… Less powerful languages are usually easier to secure… Because programs in simpler languages are easier to analyze, it’s also easier to identify the security problems that they do have”
Summary: Simple is more powerful than complex. Simple is more secure than complex. A wild wild west environment like the world wide web should be implemented with the simplest language possible, such as HTML.
“a variety of characteristics that make languages powerful can complicate or prevent analysis of programs or information conveyed in those languages, and it suggests that such risks be weighed seriously when publishing information on the Web. Indeed, on the Web, the least powerful language that’s suitable should usually be chosen.”
Fast forward to today, and we’re dealing with a new Internet over which we send real money and where we want our apps to securely function with minimal maintenance long after their original creative teams move on. The “Rule of least power” design principle has never been more relevant than today.
This is why I believe a “less powerful” standardized markup-driven approach is better for building mobile apps on crypto-protocols, instead of building “powerful” apps that end up being more of a liability in the long run.
As a protocol developer, your goal shouldn’t be to build a single monolithic app — you’re not an “app developer”. Instead, your focus should be 100% on making it easy for anyone to embed your protocol into their apps and open it up as widely as possible.
Hypothetical example: Augur
In the hypothetical example above, Augur has multiple smart contracts that make up the entire experience. The Augur team *could* go for building a single all-in-one app themselves, but what good would that do for decentralization?
The cool thing about building a protocol is that you can let anyone build their own interpretation of it, optimized to specific needs. The adoption should be determined by the free market. Building a “reference” implementation might be good, but that shouldn’t be your goal. The goal is to make it as easy as possible for your community members Alice, Bob, and Carol to build their own custom apps on top of it. The best way to do that is to write your app in a language that’s as forkable as possible, which in my to my eyes is a markup approach.
Let’s take this even further.
Today, we have only a single dominant protocol — HTTP. However, the mobile apps of tomorrow will be multi-protocol.
The current paradigm of “mobile apps” is all about building a single monolithic app which the developer has 100% ownership over. This was a natural choice in a “client-server” world where it is assumed that the developer of a mobile client also owns the server. For example, Facebook app connects to Facebook server, Twitter app connects to Twitter server, etc. In that world, it totally makes sense for the client developer to build a monolithic app, and that’s what we’ve been accustomed to until now.
But in the age of decentralized protocols, one app can be powered by multiple protocols. One app can be a “mashup” of multiple ownerless protocols.
There is no “Augur app”, “0x app”, “Decentraland app”, etc. That’s an old way of thinking.
Instead there will be apps that use all of these protocols together within a single app.
The problem is, achieving all this is not as easy as it sounds. We’re dealing with real money here and integration is surely not as easy as running npm install
. The conventional approach for building any kind of app today is:
This has been great for the age of centralized and trusted app providers, but in the world of decentralized and trustless protocols, it’s too risky because so many things can go wrong on the app developer side no matter how secure the protocol is.
After all, it is no secret that highly coupled dependencies can introduce a cascade of security vulnerabilities:
The best way to avoid this problem is to… avoid dependencies, and simplify!
A Plea for Simplicity_Ask any 21 experts to predict the future, and they're likely to point in 21 different directions. But whatever the…_www.schneier.com
As Bruce Schneier preaches in the article, you can’t secure what you don’t understand.
Based on these assumptions my proposal for building mobile apps is to build them as sandboxed, loosely coupled, dependency-free containers:
Native Mobile View as Microservice_How sandboxed views talk to each other in Jasonette_medium.com
$href
for moving forward, and $ok
for returning backward) and sometimes app-wide shared global variables.href
attribute to point to View C instead of View B)This design principle makes sure that:
If you’re a developer, you’re probably aware of the whole battle between “Native vs. HTML5”. Proponents of these two factions have been fighting over which will become the single dominant platform for building mobile apps.
A better way to look at this problem is to think of how to blend them together so seamlessly that the integration is almost unrecognizable and therefore the question becomes irrelevant.
The rule of thumb is to build apps as natively as possible, but for certain cases where it makes sense to integrate HTML components — such as graphic-heavy visualization —you should be able to do so in the most seamless manner.
Imagine building a simple game app, you could:
And this is only possible when you move away from the mindset of “only one approach wins” and focus on integrating the two in the best way possible. Below are examples of how native components and HTML components blend in perfectly together, WITHOUT having to modify the HTML at all:
I talk about this further in another article:
How to Turn Your Website into a Mobile App with 7 Lines of JSON_A New Approach for Blending Web Engine into Native Apps_medium.freecodecamp.org
In this article, I explained how I took an existing web3 DApp and turned it into a native mobile app. The key takeaways from the approach:
The first two is similar to how web browsers work, and the third is like how microservices work. Combining these I have proposed a unique architecture for building secure mobile apps.
The purpose of this post was NOT to claim this is the “ultimate solution”, but to propose a mental framework for thinking about this topic, as well as an actual functional implementation to support the hypothesis.
I think this topic of “what would the frontend in the age of decentralized protocols look like?” is not really talked about much in the community because:
But mobile apps are inevitable if you want mainstream adoption, and we need to start thinking differently about how an app will work in the blockchain world.
I am excited about decentralized technologies because it’s very aligned with my view of the future, and am planning on exploring this field further. Here are some of the themes I am thinking of:
If you have any suggestions or feedback, please share. Also, stay in touch if you’d like to follow the journey. I’d love to hear from you!
Where to find me:
Chat with me on Slack: https://jasonette.now.sh/
Follow me on Twitter: https://twitter.com/gliechtenstein
Follow me on Medium: https://medium.com/@gliechtenstein
Contribute to Jasonette on Github: https://github.com/Jasonette
Follow Project Jasonette on Twitter: https://twitter.com/jasonclient
Subscribe to Jasonette Newsletter: https://docs.jasonette.com/#mc-embedded-subscribe-form