How to Create the World’s First Mainstream DApp
Despite the promise of decentralised applications, user experience is still not ready for mass adoption. There are plenty of projects aiming to improve this. Next-generation wallets, aimed at competing with Metamask, are working to hide the plumbing of Web3 injection. Some prime examples are Torus, Fortmatic, Portis, Unilogin and Authereum. However, in my opinion, none go far enough.
Hiding the Plumbing
My main gripe is one I’ve had since I initiated myself with DApps several years ago. As a user, every time I want to send a transaction on the Blockchain, I’m prompted with an ugly popup asking me to confirm, warning me of the cost, and scaring me away. As someone who’s been initiated in the space for a few years now, this isn’t as big a deal for me. But back then it was, and it still exists. I know for a fact that newcomers in the space are met with the same scary popups every time they try to do something. It’s offputting and is the main reason why the bounce-rate on DApps is so high.
I get it, as a platform you need to make the user aware that an operation will cost money. The last thing you want as a platform is to be discredited because you didn’t warn users about the cost of usage, and your gas costs unknowingly drained their accounts of Ether. However, there are much better ways of doing this than the currently accepted norm.
Take a look at figure 1. Unless you’re very well acquainted with Ethereum wallets, DApps and the industry in general, you’re not gonna know what on earth this popup means. Some users will think the whole site bogus since popups emanating from button clicks is often considered shady practice. Yet here, it is the norm. And it appears every time a user wants to interact with a smart contract.
Not only that, but the fact that a whole extension needs to be installed to even be able to interact with DApps seems archaic. This is slowly changing. Opera have released DApp support in their mobile browser, and other wallets come with built-in DApp browsers now. But these are all so niche, they’re most definitely not mainstream.
Short of Google releasing DApp support for their Chrome Browser, or Mozilla for Firefox, the problem will still exist. It doesn’t matter how fancy you make the popups (Fortmatic has some yummy rounded edges), which niche products support Web3 injection, the problem remains.
What should be done?
The users who are using Metamask and other injected Web3 providers already know how they work, they are experienced users who aren’t afraid of DApps. Focussing on making that experience more flashy or smooth or rounded is a waste of time in my opinion. It’s not going to make mainstream users flock to your platform, because you’re not solving their issue. Their issue is the understanding of what’s happening.
Instead of focussing on making the injected Web3 experience more streamlined, aim to scrap it altogether. Build a platform that allows users to interact with smart contracts without even knowing there are smart contracts or a Blockchain even there. Make that clear to investors and enthusiasts, but for the masses, remove it entirely. Think like a bank. Banks don’t show off the internal plumbing of their systems and get users to sign off every little decision, they obfuscate it so that you don’t need to worry. They handle the heavy lifting, users don’t see it.
But how can this be done? Most DApp development tutorials teach Web3.js or Web3.py and how those libraries are used to interact with the injected Web3 instance in a browser. This is how most DApps are built, and is great for exposing the plumbing and getting Metamask to show those hideous popups. Like I’ve said, great for advanced users, but these libraries can also be used to hide the plumbing, not requiring Web3 support on the client-side.
Why not build a platform that doesn’t require injected Web3. Instead, allow users to signup using their email and a password, or even social logins like Twitter, Google and Facebook. Make it feel familiar to them. OK, so you might need some other skills if you’re new to development, but tried and trusted frameworks like Laravel do this stuff out of the box. No Metamask, no client-side Web3.
Once they’ve logged in and reached your dashboard, let them create an account. By this, I mean let them click a button, which creates a new Ethereum address on the backend.
“But what about private keys?” I hear you ask.
Firstly, for the mainstream user, keeping private keys in the possession of the end-user is not as much of a concern. I completely understand that holding any private keys centrally is a bad idea, goes against the whole premise of Blockchain technology and should be minimised, if not eradicated.
Secondly, I’m not suggesting that we store private keys as plain-text, or even hashed values. Both Web3.js and Web3.py have encryption and decryption functions which take the key, and a password of the user’s choice to make their keys unbreakable (Scroll down to learn how to use these functions).
So storing these keys alongside their account on your platform is entirely possible. It removes the need for exposing Web3 and requiring Metamask.
Focus on Adoption
Let’s say you’re building a paid platform that has Ethereum Smart Contracts on the backend. You know your users will need to interact with them but you don’t want to require basic knowledge of Metamask and wallets before they can use it. They want to just use your product, not spend hours learning about Web3. Start by building a platform that allows registration and login via Facebook, Google and other social networks.
Build a dashboard that enables the user to create an account. Call it a “user” or something that makes it even more relatable if you’re worried that Blockchain terminology will scare them off. When they do this, ask them for a pin, or an encryption password, or just use their login password to encrypt their private key. Store that encrypted version in the database alongside their user details.
You know transacting on the Blockchain is not free, and your product isn’t free either. FIAT is still the top dog in currency-land. Make that the primary payment method with Stripe or something similar. Whatever your payment structure looks like, whether it’s a one-off fee or a subscription model, load up the user’s wallet with Ether when you receive their payment. For all they know, they’ve just paid their monthly fee to you, but you know that you’ve topped up their account so that they can start interacting with your Smart Contract ecosystem.
Any time they go to submit a transaction to your smart contracts through your platform, your platform is in control of how that message is portrayed to the user. Since their key is encrypted in the database, a request for the pin is all that’s needed to decrypt the key and submit the transaction from their account. This is common practice with traditional banking apps, and there’s no prompting the user with ugly Metamask confirmations. Controlled, and exactly how you want to present it. Make the customer feel comfortable with it, make it familiar, because that’s what they’re used to.
Instead of exposing functionality on the front end, which inevitably requires Metamask or another Web3 wallet, let’s walk through how we can create an account, generate an encrypted version of the account with a password, then decrypt it upon user request using Web3.py server-side. This functionality is also available in Web3.js as well.
Inside a python terminal, run the following commands:
# Import the Web3.py library
from web3 import Web3# Set your Infura url - obtained from the Infura dashboard
infura_url = "https://mainnet.infura.io/v3/YOUR_INFURA_KEY"# Initialize web3 instance
web3 = Web3(Web3Provider.HTTPProvider(infura_url))# Create an account when the user requests
# This will create a new account object with
# an address and a private key
new_account = web3.eth.account.create()# Encrypt the account to store in your database
keystore = new_account.encrypt(user_password)
By storing this encrypted
keystore, the platform does not know what the private key is. The only way to decrypt and sign transactions would be to know the
userPassword value. Let’s take a look at how to do that.
# Retrieve the private key from the keystore and user password
priv_key = web3.eth.account.decrypt(keystore, userPassword)
This private key is all that’s needed to sign transactions on behalf of that address.
If you’re interested in Blockchain Development, I write tutorials, walkthroughs, hints, and tips on how to get started and build a portfolio. Check out some of these resources: