Skip to content

Build a Chain Abstracted App

For this tutorial, we will be building a chain abstracted app, powered by the Biconomy Modular Execution Environment!

Core concepts

The app which we build in this guide will leverage all the latest features available in AbstractJS SDK and the Biconomy stack! Some highlights:

Goals

We want to build an app with the following features:

  • User sees a unified balance across all chains
  • User can deposit to any AAVE market in a single signature
  • If a user has an already open position on AAVE, they can "rebalance" their position to another chain with a single signature.

The entire interface should be extremely straightforward for the user, with no chain switching, bridging or managing gas.

Building the app

Creating a New Project

For this tutorial we'll be using bun to create a new project.

If you don't have bun, you can install it by running:

Install Bun
curl -fsSL https://bun.sh/install | bash

Then create a new project called chapp-example

Create a new project
mkdir chapp-example & cd ./chapp-example & bun init

Install Required Dependencies: AbstractJS and Viem

Install AbstractJS and Viem
bun add @biconomy/abstractjs viem

Create a TypeScript File

Create app.ts
touch app.ts

Connect to the Smart Account

Our chain abstracted app will be powered by the Biconomy Nexus smart account. Since we're working in a multichain environment, AbstractJS comes with a helpful utility function to manage instances of smart accounts across multiple chains.

In this example, we'll create a smart account which has an EOA wallet as the owner. In order to easily create an EOA for testing purposes, we'll create the EOA through a viem utility, by providing a private key.

Create EOA signer
const eoa = privateKeyToAccount('0x... Private Key Goes Here')

Then, let's connect to our Smart Account with the utility function:

Initialize Multichain Smart Account
const mcNexus = await toMultichainNexusAccount({
  chains: [optimism, base, polygon, arbitrum],
  signer: eoa
})

Initialize the meeClient

In order to execute transactions through the Biconomy Superbundler, we need to establish a connection to it. AbstractJS makes this easy with a helper function:

Connect to MEE Node
const meeClient = createMeeClient({
  account: mcNexus
})

Fund the Smart Account Address

Fetch the Smart Account address on the chain where you want to fund your wallet. For example, let's fetch the address for Optimism

console.log(
  mcNexus.deploymentOn(optimism.id).address
)

Then send USDC to the Smart Account address!

Load the Required Smart Contracts

For this app, we'll need access to three contracts.

  • USDC Token Contract
  • aUSDC Token Contract
  • AAVE V3 Pool Contract

In order to load the AaveV3Pool contract, we can simply call the getMultichainContract utility function and load it up with the addresses of the AAVE Pool on different chains:

Multichain Contract
const mcAaveV3Pool = getMultichainContract({
  abi: parseAbi([
      "function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)",
  ]),
  deployments: [
      ["0x794a61358D6845594F94dc1DB02A252b5b4814aD", optimism.id],
      ["0xA238Dd80C259a72e81d7e4664a9801593F98d1c5", base.id],
      ["0x794a61358D6845594F94dc1DB02A252b5b4814aD", polygon.id],
      ["0x794a61358D6845594F94dc1DB02A252b5b4814aD", arbitrum.id]
  ],
});
Import and Use USDC
import { mcuSDC } from "./utils/tokens";
 
const address = mcUSDC.addressOn(optimism.id)
 
console.log(address)

Get the Unified Multichain Balance