paint-brush
The Path to a Seamless Web3: Account Abstraction from Flow (Part 1)by@alvinslee
398 reads
398 reads

The Path to a Seamless Web3: Account Abstraction from Flow (Part 1)

by Alvin LeeSeptember 20th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

The user experience of web3 apps can be clunky and pose a barrier of adoption for those not familiar with blockchain and wallets. Flow offers a walletless onboarding experience through account abstraction. We walk through how to set up a walletless dApp in this two-part series.
featured image - The Path to a Seamless Web3: Account Abstraction from Flow (Part 1)
Alvin Lee HackerNoon profile picture


Despite the advancement of dApps’ capabilities over the past year, adoption has been slowed by terrible user experience. Users are required to complete a complicated and onerous series of steps—download a wallet, learn about gas costs, obtain tokens to pay gas, save seed phrases, and more. This poses a significant hurdle for users new to the blockchain, or those who are just uncomfortable with holding crypto. Often, they just give up.


To solve this problem, walletless dApps on Flow have emerged. With this approach, users can easily sign up for dApps using credentials they are already comfortable with (social logins, email accounts). This allows them to get started quickly, without needing to understand the complexities of wallets or blockchain.


In this two-part series, we’ll explore how walletless dApps on Flow work. We'll look at some use cases and walk you through the steps of building and deploying your wallet-less web3 dApp using the Flow Wallet API and account abstraction.


Here in part one, we'll focus on building the backend for our walletless dApp. In part two, we'll wrap up the walkthrough by building the front end.


Content Overview

  • How Flow Solves Web3 Onboarding
  • Use Cases of Account Abstraction
  • Building a Sample Walletless Login dApp
  • Set up Flow Wallet API application
  • Configure Environment Variables
  • Update the docker-compose.yml File
  • Test the Flow Wallet API Application

How Flow Solves Web3 Onboarding

Flow is a highly scalable blockchain with a design philosophy that prioritizes mainstream use: easy user logins, mobile-ready, fast development time, 99.99% up-time, and more. It’s made for dApps that have real-world usage


Account abstraction (AA) on Flow falls right into this philosophy. AA, in combination with hybrid custody, creates a walletless onboarding experience for users. What does this mean?


Typically, accounts on a blockchain are owned either by a user with a private key—called an externally owned account (EOA)—or by a smart contract—called a contract account.


Account abstraction combines these ideas. It allows the user to control the wallet while abstracting away the idea of the wallet altogether by letting the contract also have control. On Flow, this is called Hybrid Custody.


Use Cases of Account Abstraction

There are lots of advantages to this “account delegation.” Since one account (the child/EOA account) can delegate control to another account (the parent/app account), developers can provide users with a seamless onboarding and in-app experience while giving them a sense of actual ownership and self-sovereignty. This is particularly useful for new users who are not familiar with the intricacies of blockchain technology and can help increase adoption and engagement with the application.


For example, developers can build apps that create wallets for users, manage keys and transactions, and even abstract away the blockchain altogether. But in the end, the user still has control and ownership over any assets in the wallet.


Other use cases include:


  • Key recovery with multi-sig transactions
    • An account may be set up to require multiple signatures to complete a transaction. This creates a wide variety of new use cases and enhances the usability of Web3 apps.\
  • Gasless experiences with sponsored transactions
    • The stress that comes with paying fees—before newbies can use a Web3 app and execute a transaction—can be a barrier. Sponsored transactions give room for developers to subsidize these charges on behalf of users.
  • Seamless experiences with bundled transactions
    • Flow’s Cadence programming language, which introduces new features to smart contracts, also separates contracts from transactions. It supports bundling transactions from several contracts into a single transaction at the protocol level.
  • Social logins with wallet-less onboarding + hybrid custody
    • Flow enables its developers to deliver a familiar experience while progressively exposing new users to the benefits of Web3. Users can realize the benefits of both custodial and non-custodial experiences, which is what hybrid custody entails.


All this together makes it much easier for users to get started with web3 dApps.


Building a Sample Walletless Login dApp

So let’s next walk through creating a walletless dApp. We’ll build a dApp that integrates Google social login/signup and creates a Flow wallet for the user on signup time.


Here is a quick breakdown of what we’re going to do in part one of this walkthrough:


  1. Set up a dockerized Flow Wallet API application to use the Flow Testnet
  2. Test the Flow Wallet API Application


Then, in part two:

  1. Create a new Next.js application
  2. Set up Prisma for backend user management
  3. Build the Next.js application frontend functionality
  4. Test our Next.js application


Are you ready? Let’s go!

Set up Flow Wallet API application

To make our lives easier, we’ll use the Flow Wallet API. This is a REST HTTP service that allows developers to quickly integrate wallet functionality into dApps. This API was developed in Golang, so knowledge of Go will help you, though proficiency is unnecessary to make this app work! The Flow Wallet API is currently not maintained. However, at the time of writing, the API was working perfectly.


Clone the project folder with the following command:

$ git clone https://github.com/flow-hydraulics/flow-wallet-api.git


To facilitate the development, we will use Docker. If you don't have it installed on your OS, you can find instructions for it at this link: https://docs.docker.com/engine/install/


From the terminal, navigate to the newly created flow-wallet-api directory.


I recommend taking the time to review the folder structure. This API was very well done and is a complete code with unit tests included! To make this article as short as possible, we will focus on executing the code.


MacOS M1 chip config

Note: If your computer is a Mac using an M1 chip, you will need to change the Dockerfile file in the docker/wallet/ folder. If you are not using an M1, you can skip this section.


In Dockerfile, edit the first line of code. We will change the Golang version used by the container to:

FROM golang:1.20rc1-alpine3.17 AS dependencies


You will also need to change the value of the GOARCH field:

GOARCH=arm64


That's it! These are the required changes in Mac M1 operating systems.


Configure Environment Variables

Before we can spin up the Flow Wallet API, we need to make some configuration changes. The first step is to rename the .env.example file to .env. The application will use this file to import the environment variables.


Within the .env file, we need to change some values.

Flow network fields

Since we will be running the application over Flow’s Testnet network, we need to change the environment variables FLOW_WALLET_ACCESS_API_HOST and FLOW_WALLET_CHAIN_ID. In the  .env  file, comment out the following lines:


# emulator
# FLOW_WALLET_ACCESS_API_HOST=localhost:3000
# FLOW_WALLET_CHAIN_ID=flow-emulator


Then, uncomment the following lines:


# testnet
FLOW_WALLET_ACCESS_API_HOST=access.testnet.nodes.onflow.org:9000
FLOW_WALLET_CHAIN_ID=flow-testnet


With this change, we’ve modified the configuration of the application to use the Testnet network.

Flow admin account fields

To use the Testnet, we need to create a Testnet account and update the  FLOW_WALLET_ADMIN_ADDRESS  and  FLOW_WALLET_ADMIN_PRIVATE_KEY fields inside the .env file.


To create a Flow Testnet account, you must first install the Flow CLI on your operating system. You can find instructions on how to do this here.


With Flow CLI installed, run the command:

$ flow keys generate


This command will generate an asymmetric public-private key pair. Save the private key somewhere. Then, copy the public key—we will use it in the next step to create an account on the Flow blockchain!

Create a Flow Testnet account

Open the browser on the Flow faucet: https://testnet-faucet.onflow.org/


In the first input, paste in the public key you just generated. Leave the rest with the default settings, then perform the CAPTCHA verification and click the Create Account button.



This will generate a Testnet Address.


Copy the address and use it as a value for the FLOW_WALLET_ADMIN_ADDRESS field in the .env file. Also, update the FLOW_WALLET_ADMIN_PRIVATE_KEY field with the private key that you generated in the previous step.


In my case, it would look like this:

FLOW_WALLET_ADMIN_ADDRESS=0x7cc7be2796e8cf29
FLOW_WALLET_ADMIN_PRIVATE_KEY=73bc408436c14befd74cb01fa4c54217c6c860ff97df1a77a3063a2807c7067f


We’re ready! Our Testnet account has been created. This is the admin account that will execute, sign, and pay for the creation of new wallets for our application.

Proposal key field

Within an account, it is possible to have several proposal keys. As we will call several transactions with the same account to avoid concurrency problems, we will need to create new proposal keys for the admin account. You can read more about proposal keys here.


We’ll change the configuration in .env to create 10 new proposal keys. For our tests, this is a sufficient amount. However, if you start having concurrency problems when executing transactions, you can change this value and restart the application.


FLOW_WALLET_ADMIN_PROPOSAL_KEY_COUNT=10


Idempotency middleware field

We’ll also add a property to the .env file to disable idempotency middleware. Since we are just testing the application (and using it to facilitate our post requests), we will leave it disabled by setting the following value to true. However, it is recommended to activate it in a production environment.


FLOW_WALLET_DISABLE_IDEMPOTENCY_MIDDLEWARE=true


Update the docker-compose.yml File

Since we made some changes to our .env (including using the Testnet network and disabling idempotency middleware), We can remove a few lines of unnecessary code in the docker-compose.yml file. Our application will not be using the redis and emulator containers. So, we can remove them.


After removing them, your docker-compose.yml file will look like this:

version: "3.9"

networks:
  private:

services:
  db:
    image: postgres:13-alpine
    environment:
      POSTGRES_DB: wallet
      POSTGRES_USER: wallet
      POSTGRES_PASSWORD: wallet
    networks:
      - private
    ports:
      - "5432:5432"
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "pg_isready --username=${POSTGRES_USER:-wallet} --dbname=${POSTGRES_DB:-wallet}",
        ]
      interval: 10s
      timeout: 5s
      retries: 10

  api:
    build:
      context: .
      dockerfile: ./docker/wallet/Dockerfile
      target: dist
      network: host # docker build sometimes has problems fetching from alpine's CDN
    networks:
      - private
    ports:
      - "3000:3000"
    env_file:
      - ./.env
    environment:
      FLOW_WALLET_DATABASE_DSN: postgresql://wallet:wallet@db:5432/wallet
      FLOW_WALLET_DATABASE_TYPE: psql
    depends_on:
      db:
        condition: service_healthy


Note that we also removed some lines from the api service:


  • FLOW_WALLET_ACCESS_API_HOST and FLOW_WALLET_CHAIN_ID in the environment section.
  • Lines for redis and emulator in the depends_on section


We spin up our containers with the following command:

$ docker compose up


Test the Flow Wallet API Application

When we run the above command, Docker will spin up the following:


  • flow-wallet-api-db-1: This is the PostgreSQL database container where all data will be stored, including the users’ private keys. Remember that we are only running the application in a test environment, using the Flow Testnet network. If you use this API in production (Mainnet), protect the users’ private keys. One option is to use key management system services. The Flow Wallet API has easy and fast integration with Google KMS and AWS KMS.
  • flow-wallet-api-api-1: This is an application in Golang that connects to the Flow network and performs actions such as creating wallets, transactions, scripts, and much more.

Done! Our application runs through these two Docker containers, We can make calls using (the default) port 3000.


All endpoints available in the application can be found in the documentation here.

Check the Application’s Health

The endpoint to check if the application is healthy is /v1/health/ready.

We send a curl request to check this endpoint, and this is what we receive as a response:


$ curl -X GET -i http://localhost:3000/v1/health/ready


HTTP/1.1 200 OK
Vary: Accept-Encoding
Date: Fri, 05 May 2023 17:27:05 GMT
Content-Length: 0


With the 200 response, we are assured that our application is up and running.

Create a Wallet

Creating a new wallet via the API is very easy! We send a POST request to the  /v1/accounts  endpoint.


$ curl -X POST http://localhost:3000/v1/accounts

{
  "jobId":"2876f90d-d9ec-4007-935b-4aba3cb8e45e",
  "type":"account_create",
  "state":"INIT",
  "error":"",
  "errors":null,
  "result":"",
  "transactionId":"",
  "createdAt":"2023-05-05T17:29:34.800299551Z",
  "updatedAt":"2023-05-05T17:29:34.800299551Z"
}


Under the hood, the API creates an asymmetric key pair and executes a transaction on the Flow blockchain to create an account.

Jobs

Since a transaction takes a few seconds and can fail, the API creates jobs.


These jobs are records/units that are stored in the database. Each time a transaction is called or queued, a job is created. The status of the transaction is stored in this job.


Notice how the transaction state returned by our call above is INIT. The API is monitoring the account creation transaction.

Get Job Data and Account Addresses

To get the updated state of this job, we can send a GET request to the  /v1/jobs/{JOB_ID}  endpoint.


$ curl -X GET \
  http://localhost:3000/v1/jobs/2876f90d-d9ec-4007-935b-4aba3cb8e45e

{
  "jobId":"2876f90d-d9ec-4007-935b-4aba3cb8e45e",
  "type":"account_create",
  "state":"COMPLETE",
  "error":"",
  "errors":null,
  "result":"0xb23d449bc23d9d04",
  "transactionId":
    "ab68527578c323b68caf9d1b1533ebf4a3486f22b0d6f7df4339c57e48d9c4ca",
  "createdAt":"2023-05-05T17:29:34.800299Z",
  "updatedAt":"2023-05-05T17:29:47.507803Z"
}


We see the result, with a newly created address. It is also possible to check all addresses created by the application using the /v1/accounts endpoint.


$ curl -X GET http://localhost:3000/v1/accounts

[
  {
    "address":"0xb23d449bc23d9d04",
    "keys":null,
    "type":"custodial",
    "createdAt":"2023-05-05T17:29:47.504906Z",
    "updatedAt":"2023-05-05T17:29:47.504906Z"
  },
  {
    "address":"0x7cc7be2796e8cf29",
    "keys":null,
    "type":"custodial",
    "createdAt":"2023-05-05T17:25:51.847239Z",
    "updatedAt":"2023-05-05T17:25:51.847239Z"
  }
]


With our wallet API working, we can start implementing the application that will send requests to the wallet API to create new accounts. We'll cover this in part two of our walkthrough.



Also published here.