Circle User-Controlled Wallets Sample App - Backend Server

Check out the live demo first to see what to expect!

Overview

The backend server is a crucial component of the User-Controlled Wallets Sample App, responsible for communicating with the Circle Web3 Services API. It leverages the Circle Web3 Services Node.js SDK to enable the client-side application to interact with Circle's Web3 Services, such as user-controlled wallets, which can perform gasless transactions because they are Smart Contract Accounts (SCA) linked to Circle's paymaster policy.

Prerequisites

  1. Sign up for Circle's Dev Console.

  2. Set up Testnet API key, see guide.

  3. Install nvm and yarn, these are required development tools.

  4. Important: Set up Sample App Frontend UI as well to get the end-to-end experience. Please be aware that the SDK user token will expire after 60 minutes.

Configure the Sample App

  1. Run yarn env:config, and you will see a .env file generated in the root directory.
  2. Paste your API key into the .env file.

Get Started

Run the following commands to start the server with an in-memory SQLite database at localhost:8080:

nvm use
yarn install
yarn dev
  1. nvm use: set node version.
  2. yarn install: install dependencies.
  3. yarn dev: run the server, hot reload is supported.

Architecture

The backend server will play the role as Your Server, see details. image

Code Structure

We use Express as web framework and SQLite as default database.

  • The main logic to interact with Circle Web3 Services Node.js SDK is under src/controllers:

    • In onboarding.ts, we use the SDK to generate a user token for both our Sign Up and Sign In functions by calling the createUserToken:

        const tokenResponse = await circleUserSdk.createUserToken({
          userId: newUserId
        });
    • Majority of files under src/controllers will require this user token to be passed within the header. For instance, creating a transaction with circleUserSdk.createTransaction(...) in transactions.ts, req.headers holds the token value and req.body holds all the parameters that the client can pass in as an object. Once authorized and configured from the client, the SDK uses Programmable Wallets to send on-chain transactions:

          const response = await circleUserSdk.createTransaction({
            userToken: req.headers['token'] as string,
            fee: feeConfig,
            idempotencyKey: req.body.idempotencyKey,
            refId: req.body.refId,
            amounts: req.body.amounts,
            destinationAddress: req.body.destinationAddress,
            nftTokenIds: req.body.nftTokenIds,
            tokenId: req.body.tokenId,
            walletId: req.body.walletId
          });
  • Shared logic for the routers live in src/middleware:

    • auth.ts: logic to parse and validate user token
    • errorHandler.ts: logic to handle errors
    • validation.ts: logic to handle incoming parameter type
  • src/services holds external resources that the server needs:

    • userControlledWalletSdk.ts: will initialize an instance of the user-controlled wallet sdk to be used by the controllers.
    • db/: configures the Sqlite database for the user credentials.
  • src/app.ts sets up the express router configurations and sets the base path and sub paths for the controllers. Imported by src/index.ts as the entry point of the server.

  • The above are the most important files to get an understanding of this server. All other files are specific to this server and not crucial to using Circle Web3 Services Node.js SDK.

Happy Coding!

Additional Resources