# What is Zerowallet

Users can use your dapp onchain without having to install a wallet or paying gas

Zero wallet is an SDK that allows developers to allow users to make on chain interactions without having to install a wallet or pay gas fees.&#x20;

Zerowallet is ideal for non-financial transactions in dapps. Some examples :&#x20;

* Creating a post on an on-chain social media (E.g Lens)
* Storing data on a SaaS product, on-chain (E.g Questbook)
* An identity app to create and store credentials (E.g. Credport)

Zero wallet creates a throw-away wallet in-(d)app the first time a user opens the dapp. The wallet is retained in persistent storage. For example, on browser - `localStorage` and in mobile apps in `SharedPreferences`

We do not recommend this wallet to be used in financial transactions because, of the lower security of an in-app wallet. Metamask, Phantom or WalletConnect are more secure.&#x20;

**Zerowallet is best used in dapps where the transactions need to be recorded on chain for the purpose of censorship resistance and permanent record of behaviour.**

The integration is simple and consistent with libraries like ethers.js and wagmi


# Why we built Zerowallet

Zerowallet brought to you by Questbook

Zerowallet has been developed by the team behind Questbook.xyz

Questbook is a grants management tool for enabling maximum decentralization processing grants. All the applicants must apply to the grant program via an onchain transaction. That way their data is stored permanently with censorship resistance, and the community can make decisions on who must get the grant and who must not.&#x20;

We realized the only way to do this is to have all of the user actions must be on chain.&#x20;

But there were significant drawbacks&#x20;

### Annoying Confirm Buttons

We expect users to have 10-20 actions per session.&#x20;

If the user has to press on a confirm button on their wallet app/extension each time they have to do a simple action - results in *huge* user friction.&#x20;

Confirm buttons were designed for financial transactions. It doesn't make sense to confirm a transaction for every action of the user that needs to be recorded for downstream use.

### Gas fees? Yuck

Who likes paying gas fees? Especially for dapps that are looking to onboard new users to crypto - it is impractical to expect the users to install a wallet app, figure out how to buy some tokens for paying gas, transfer it to their wallet and then do a simple in-app actions.

Gas fees is for the crypto-native. We need to let people onboard into dapps without having to hop through all the hoops even if they've had no experience in crypto before. The UX should be at-par as, if not better than,  that of traditional websites and apps. You open the app, and start interacting.&#x20;

### Switch chains - is a huge anti pattern

Switching chains is an anti pattern that is probably Metamask's biggest sin. Why should the end user know what is the underlying chain? Does a user need to know the database (Mysql, Postgres, Mongo) the website is using to interact with it? No. Why should they know the blockchain on which their transactions are stored?

Zerowallet lets the developer decide which chain the transactions will be sent to and the transactions are sent there without asking the user to switch networks on their wallet. Because, the user interacting with a dapp that's using zerowallet, they don't even need to have a browser extension or wallet app installed!

We built Zerowallet to give our users at Questbook a great experience interacting onchain. We have now open sourced the library for broader use.


# How does Zerowallet work?

We'll cover all components used by the Zerowallet with an example flow in the end of the doc

## In-app wallet (Zerowallet)

For each user interacting with your dapp, we will create an in-app wallet that will be the signer of all transactions going into the blockchain. This wallet is stored on your `localStorage` in case of a browser or in the `SharedPrferences` in case of a mobile app.&#x20;

The Zerowallet goes through three steps to be able to send a gasless transaction:

1. Send the raw transaction to the backend service to be built with correct types and structure
2. Sign the retrieved transaction
3. Send the transaction to the backend service to execute it on-chain

In case the user wants to use this wallet on a different device, we support several recovery mechanisms to import the wallet onto another device (or to restore the wallet in case the storage was cleared). See [#recovery-mechanisms](#recovery-mechanisms "mention")&#x20;

## Smart Contract Wallet (SCW)

The SCW (Smart Contract Wallet) is the on-chain transaction executor of the[#in-app-wallet-zerowallet](#in-app-wallet-zerowallet "mention"). There's a one-to-one mapping between each Zerowallet and SCW. The SCW is the one that will pay the gas and relayingrelay all transactions to the blockchain on behalf of the Zerowallet. Since the SCW will be the one sending the transactions to the blockchain, we know that it will be the `msg.sender` on any contract. So basically the SCW will be the owner and executor of any transaction signed by the Zerowallet.

## Zerowallet Backend Service

This is where transactions will be sent after the Zerowallet signs the transaction.[#authentication](#authentication "mention") checks and transaction processing will happen here. If everything passes, the transaction will be sent to the SCW to be executed on-chain. See [Running the docker service](/running-the-docker-service).

## Gastank

All SCWs will get the gas they need to carry out transactions from the gastank. You will be the one deciding which gastank should be used for each transaction. Each gastank is responsible for one chain, and it's possible to create multiple gastanks on the same chain.&#x20;

## Authentication

Only authorized Zerowallets are allowed to send gasless transactions. You decide which wallets to authorize and when to authorize them. We create a token`nonce` in the backend service for each authorized wallet with an expiration date. When it expires, you decide whether you want to refresh it or not.&#x20;

When the Zerowallet sends a request to execute a transaction to the backend service, it should first retrieve its corresponding nonce, sign it, and append the signature to the request. In the backend service, we will check if the signer matches one of the authorized Zerowallets.

## Recovery Mechanisms

To allow users to log into their zero wallets on new machines, Zerowallet allows users to backup and recover their wallets using Google Drive or using a web3 wallet like Metamask. Learn more[Recovery](/recovery).

## Example flow

A user enters the website with Zerowallet integrated. The user will be asked to take some action to prove that they're eligible to use gasless transactions (here you will authorize their Zerowallet). Then, when the user wants to interact with the dapp, all he has to do is press the button that triggers the contract function call. Here's what's happening under the hood:

1. Authorize the Zerowallet in the backend service (here we create the `nonce`).&#x20;
2. Retrieve the nonce linked to the user's Zerowallet and sign it.
3. Deploy the SCW for the user's Zerowallet by sending a request to the backend service (and appending the signature of the nonce to the request).
4. Send another request to the backend service to build the transaction with correct types and structure (and appending the signature of the nonce to the request).&#x20;
5. Signing the built transaction.
6. Send the final request to the backend service to execute the transaction (and appending the signature of the nonce to the request).

You can find a complete example here <https://github.com/questbook/zero-wallet-wagmi-connector/tree/main/example>


# Setting up a gas tank

As we are using Biconomy, you should first create an account on the [Biconomy Dashboard](https://dashboard.biconomy.io/). Now you can find your **Auth Token** on the Account page. You are going to use it to create gas tanks for your application(s).

In order to create a gas tank, you need to use this typescript function (**Do not create a dapp directly on Biconomy Dashboard**)

```typescript
const addGasTank = async(dappName: string, networkId: string, authToken: string) => {

	const url = 'https://api.biconomy.io/api/v1/dapp/public-api/create-dapp'

	const formData = new URLSearchParams({
		'dappName': dappName,
		'networkId': networkId,
		'enableBiconomyWallet': 'true'
	})

	const requestOptions = {
		method: 'POST',
		headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'authToken': authToken },
		body: formData
	}

	const res = await fetch(url, requestOptions)
	const resJson = await res.json()

	return { apiKey: resJson.data.apiKey, fundingKey: resJson.data.fundingKey.toString() }
}
```

You should pass the **Auth Token** (that you got from the dashboard), name, and network ID, to this function. After running this function, you will find your gastank created on the dashboard. If you press on the gas tank block, you can see all details related to your gas tank, including the API Key. This API Key will be passed to the backend service (we'll talk more about this in the next sections).&#x20;

In order to fill the gas tank, you should first connect your wallet to the dashboard (the button in the left bottom corner) and then you can fill the gas. Note that you'll need to fill the gas in the native token of the network you created the gas tank on.

You also can add limits on using your gas tank under Meta Transactions Limit section.&#x20;

For more details you can check [biconomy docs](https://docs.biconomy.io/).


# Setting up Postgres


# Setting up Google Drive Recovery

Here we demonstrate the steps for achieving Google Drive Recovery

If you are not familiar with this type of recovery or Zerowallet recovery at all, please learn more[Recovery](/recovery).

## Create a Google Cloud Project

Go to <https://console.cloud.google.com/> and log into your Google account. Now create a new project on the cloud. Add the project name and the name of your organization. Then select the newly created project.

## Enable Google Drive API&#x20;

This step allows the cloud project to utilize the Google Drive API so it can add new files and folders to the user's Drive. Navigate to the Dashboard after selecting the newly created project. Search for the Google Drive API and enable it.&#x20;

## Enable OAuth Consent Screen

The Zerowallet relies on Google OAuth 2.0 for authorization. This step is for showing users consent screens when they are setting up or initiating Google Recovery.

* Search and Go to OAuth Consent Screen. Choose the user type (internal or external) according to your needs. Add the details such as the app name, support email, domain, etc.
* Click 'save and continue' and go to the next page. Now you need to pick the scopes of the project. Click 'Add or remove scopes' then search for Google Drive API in the scopes. Select the scope: `./auth/drive.file` with the description: See, edit, create, and delete only the specific Google Drive files you use with this app.
* Click 'save and continue' and go to the next page. Next you need to add the test users for your application.
* Click 'save and continue' and go to the next page. Review the summary of the application in the last page.&#x20;

## Client ID Credentials

Go to Credential from the left sidebar. Click "Create credentials", then choose OAuth Client ID from the drop-down. Choose the application type according to your needs whether it be web or Android app, etc. Add the Authorized JavaScript origins and Authorized redirect URIs (in case of web app). If you're testing a Next JS project, for example, <http://localhost:3000> is the default URI.

After saving, copy your Client ID and use it when using the package. To set the options of the Google recovery below is an example retrieved from <https://github.com/questbook/zero-wallet-wagmi-connector/tree/main/example>

```typescript
const googleRecoveryOption: RecoveryConfig = {
    type: 'google-web-recovery',
    googleClientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!,
    allowMultiKeys: false,
    handleExistingKey: 'Overwrite'
};
```


# Recovery

We'll present an overview of the recovery mechanisms available for Zerowallet

We store the wallet in the `localStorage` of a browser. The recovery use-case is when a user logs in from another machine and wants to have the same account they had previously, or when the `localStorage` is cleared for some reason.

There are mainly two steps for recovery:

1. Setup phase: carried out when the user is logged in and authenticated. This stage entails altering the state of the zero wallet to be recoverable. Recovery can be applied only if this phase was performed.
2. Initiate phase: done when the user wants to log in. If a user needs to log into a zero wallet, he/she must have already setup the recovery (previous step) on that wallet.

All recovery mechanism support multiple accounts.&#x20;

For now, we only support Google Drive recovery (we will launch Metamask recovery soon).&#x20;

## Google Drive Recovery

1. Setup phase: the private key of the zero-wallet is exported to the user's Google Drive under the user’s control. A new folder is created on Google Drive and files of zero wallets' private keys are stored under that folder.
2. Initiate phase: we will try to detect the user’s private key stored on Google Drive. Then we will import this private key to create the corresponding zero wallet.

**NOTE:** The private keys of the zero wallets will not at any point be stored anywhere other than the user's Google Drive.

## Metamask Recovery

Let’s assume a user now has a randomly generated authenticated wallet (call it *OLD\_WALLET*) associated with some SCW.

1. Setup phase: The user is asked to sign a message from Metamask. The signed message is then used to create a new random wallet (call it *NEW\_WALLET*). Then we change the owner of the SCW from *OLD\_WALLET* to *NEW\_WALLET*.
2. Initiate phase: Similar steps to the setup. The user is asked to sign a message from Metamask. The signed message is then used to create a new random wallet. This wallet should be a valid zero wallet which is (if setup was already carried out) associated with the same SCW.


# Running the docker service

This is the Zerowallet backend service that is responsible of [How does Zerowallet work?](/how-does-zerowallet-work#authentication) and executing transactions on-chain.

### 1 - Clone this repo and cd into it

```
git clone https://github.com/questbook/zero-wallet-backend-service.git
cd zero-wallet-backend-service
```

### 2 - Fill in the config.sample.yaml file with your own config and rename it to config.yaml

Follow instructions [here](/configuring-the-yaml-file) in order to fill the `config.yaml` file.

### 3 - Build the docker image:

```
docker build . -t zero-wallet-backend-service
```

### 4 - Then run the container:

```
docker run --network=host zero-wallet-backend-service
```

### Server endpoints

This service exposes several API endpoints to be used in the frontend part, note that you should only change \<DOMAIN> to the domain where you're deploying the service.

```typescript
nonceProvider : http://<DOMAIN>/api/auth/getNonce
nonceRefresher : http://<DOMAIN>/api/auth/refreshNonce
authorizer : http://<DOMAIN>/api/auth/authorize
gasStation : http://<DOMAIN>/api/tx/send
transactionBuilder : http://<DOMAIN>/api/tx/build
scwDeployer : http://<DOMAIN>/api/tx/deploy
```


# Setting up the HTTPS server

## Option 1 : ELB

With [AWS Elastic Beanstalk](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html), you can quickly deploy and manage applications in the AWS Cloud without having to learn about the infrastructure that runs those applications.

If you are not familiar with ELB, you can see [Getting started using Elastic Beanstalk](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/GettingStarted.html).

You can deploy your server on Elastic Beanstalk, as it supports the deployment of web applications from Docker containers.

In order to deploy your server using Elastic Beanstalk, you can follow the official [AWS tutorial for deploying applications from Docker containers](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_docker.html).

Once you have your server deployed on Elastic Beanstalk, you can follow up with [AWS official Configuring HTTPS with Elastic Beanstalk tutorial](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https.html).&#x20;

## Option 2 : Nginx

The second option is to use Nginx, we already set it up inside the docker container, so you don't have to worry about Configuring it. You just need to follow the steps below:

#### 1- Adding certificate and key

In order to create a secure connection with the user’s browser, we’ll need to obtain a digital certificate and a private key. Normally, you get the certificate from a certificate authority such as [Let’s Encrypt](https://letsencrypt.org/). Make sure to install the certificate using [Certbot](https://certbot.eff.org/instructions), which will take care of reconfiguring NGINX for you.

{% hint style="info" %}
For local development you can also [create a self-signed certificate](https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-nginx-for-ubuntu-12-04). The only problem is that browsers will show a warning that the “Certificate is not Trusted” when someone visits your website. But for testing on your local machine that’s perfectly fine.
{% endhint %}

As you can see in your project root directory, we have two main directories, `nginx` and `server`. Once you have your certificate and private key, you need to add them to `nginx` directory with the following names:

* `cert.pem` for the certificate &#x20;
* `key.pem` for the private key

#### 2- Building docker-compose

Once you have your private key and ssl certificate in `nginx` directory, all you need is to build the docker-compose

```
 sudo docker-compose up --build
```

**That’s it!**

Now, if you access <https://localhost:443>, your connection will be secure.

{% hint style="info" %}
Note that our default **https** port is **443**, you can change that by replacing the listen port in **default.conf**, inside server component.
{% endhint %}

For more information, check out [Configuring HTTPS servers with NGINX](http://nginx.org/en/docs/http/configuring_https_servers.html).


# Configuring the YAML file

This is an example for the YAML file :

```yaml
 databaseConfig:
      user : "---"
      host : "---"
      database: "---"
      password  : "---"
      port: 0
      
 gasTanks:
   - name: "gasTank1"
     apiKey: "---"
     chainId: 0
     providerURL: "---"
     whiteList:  
        - "address1"
        - "address2"
        - "address3"
```

### databaseConfig

Here you add your database information as known including user, host, database, password, and port.

{% hint style="info" %}
Note that for a host.docker.internal in case of local database.
{% endhint %}

## GasTanks

This is an array of gas tanks, where each gasTank should include the following:

**name**: The name of your gas tank

**apiKey** : Biconomy apiKey for this gasTank

**chainId**: The chain id for this gas tank

**providerURL** : Link to your private provider

**whiteList** : an array of contracts addresses this gas tank is allowed to interact with.&#x20;


# Installing frontend NPM packages

```typescript
npm i zero-wallet-wagmi-connector
```

## Zero wallet connector

First of all, we need to create our wagmi connector using the `ZeroWalletConnector` class.

You can see the following example code for initializing the connector :&#x20;

<pre class="language-typescript"><code class="lang-typescript">import { chain } from 'wagmi'
import { 
    ZeroWalletConnector, 
    ZeroWalletConnectorOptions } 
from 'zero-wallet-wagmi-connector'

const zeroWalletConnectorOptions: ZeroWalletConnectorOptions;

<strong>const connector = new ZeroWalletConnector({
</strong>    chains: [chain.goerli],
    options: zeroWalletConnectorOptions
});
</code></pre>

### Parameters

```typescript
{
  chains?: Chain[];
  options: ZeroWalletConnectorOptions;
}
```

**chains** : An array containing chains to be added to the connector, you can use wagmi `chain` object. You can find more about it [here](https://wagmi.sh/react/constants/chains).&#x20;

**options :** an object of the following type :&#x20;

```typescript
type ZeroWalletConnectorOptions = {
    jsonRpcProviderUrl: string;
    store: string;
    recoveryMechanism: string;
    gasTankName: string;
    zeroWalletServerEndpoints: ZeroWalletServerEndpoints;
};
```

**`jsonRpcProviderUrl`** : link to your provider

**`store`** : Defines the way the connector stores data related to Zerowallet (e.g. private key, nonce etc.), for now we only support `browser` option for this (you need to pass `'browser'` to this param).&#x20;

**`recoveryMechanism`** : The type of the recovery mechanism you'd like to include (We only support GDrive for now - you need to pass `'google'` to this param).&#x20;

**`gasTankName`** : The name of the gas tank we want to interact with, note that this name should match the one in the backend YAML file.

**`zeroWalletServerEndpoints`** : Server endpoints that the [docker service](/running-the-docker-service) exposes, Should match the following type :&#x20;

```typescript
type ZeroWalletServerEndpoints = {
    nonceProvider: string;
    nonceRefresher: string;
    authorizer: string;
    gasStation: string;
    transactionBuilder: string;
    scwDeployer: string;
};
```

`nonceProvider` : API endpoint to retrieve the nonce for a given Zerowallet.

`nonceRefresher` : API endpoint to refresh the nonce for a given Zerowallet.

`authorizer` : API endpoint to add the given Zerowallet to the authorized users list.

`gasStation` : API endpoint to send a transaction to the blockchain.

`transactionBuilder` : API endpoint to build a transaction.

`scwDeployer` : API endpoint to deploy the SCW for a given Zerowallet.&#x20;

## Zero wallet signer

All the Zerowallet functionalities are wrapped inside the `ZeroWalletSigner` which you can access as follows:&#x20;

```typescript
const { data: signer, status } = useSigner<ZeroWalletSigner>()
```

## How to interact with Zerowallet Signer

### signer.authorize() => Promise\<void>

Adds the current user to the authorized users list, which means this user can now use all Zerowallet functionalities.

{% hint style="info" %}
Note that signer.authorize() should be called only one time for a certain user,

in case of calling this function for an authorized user, it will throw an error.
{% endhint %}

### signer.deployScw() => Promise\<void>

Deploys the [How does Zerowallet work?](/how-does-zerowallet-work#smart-contract-wallet-scw) for an authorized Zerowallet. The user should be authorized, otherwise this function will throw an error.

### signer.refreshNonce() => Promise\<void>

Refreshes the expired nonce for the given Zerowallet. The user should be authorized at least once before, otherwise this function will throw an error.

### signer.getNonce() => Promise\<string>

Returns the current nonce of signed in user. In cases of unauthorized given user or expired nonce, this function will throw errors.


# Open source

Zerowallet is a 100% opensourced public good

## Frontend

{% embed url="<https://github.com/questbook/zero-wallet-wagmi-connector>" %}

## Backend

{% embed url="<https://github.com/questbook/zero-wallet-backend-service>" %}

{% embed url="<https://github.com/questbook/zero-wallet-server-sdk>" %}


# Grants

Grants for integrating zerowallet in your dapp

If you've integrated zerowallet in your dapp, you can apply for a grant here :&#x20;

{% embed url="<https://www.questbook.app/explore_grants/about_grant/?grantId=0x1cef6208fb30fa9db779a2c3ea5d41b6f0a5fbaf&chainId=10>" %}


