Get Started with the Nexus SDK using Next JS
WANT TO SKIP THE TUTORIAL?
We created two template repos for devs to easily get started with the Nexus SDK using Next JS and Vite.
We recommend going through the tutorial first, but to each their own:
Prerequisites
The following tutorial uses pnpm
as the package manager, adjust the commands
if you’re using a different one.
-
Make sure Node.js is installed on your system. We recommend version
20.x.x
or higher. -
Set up a package manager of your choice. We use pnpm for this tutorial, but alternatives like npm and yarn work just fine.
-
Make sure you have an EIP-1193 compatible wallet provider (for example, MetaMask) installed in your browser to follow along with the tutorial.
Objectives
By the end of this tutorial you will have:
- Understood how to initialize the Nexus SDK inside a frontend environment.
- Implemented said initialization using Next JS.
- Fetched unified balances using the Nexus SDK.
WHAT IS A ‘UNIFIED BALANCE’?
You can refer to this page in our docs for more details.
What Does ‘Initialization’ Mean Here?
-
The Nexus SDK allows you to seamlessly transfer tokens across-chains using the
.transfer()
and.bridge()
functions (We’ll go through them in the following tutorials). You can also fetch unified balances using the.getUnifiedBalances()
function. -
To do any of that though, the SDK needs access to a wallet. You can do this on the frontend by using an injected wallet provider that follows the
EIP-1193
standard. -
And to do that, you need to call the
.initialize()
function of the SDK while passing the wallet provider to it. -
The flows to do this differ between the headless and the widgets SDK. We will go over both of them in this tutorial.
The .initialize()
function must be called AFTER a wallet has been connected.
Otherwise, the SDK will throw an error.
Initialize the Nexus SDK using Next JS (A minimal example using nexus-core)
Objective
In this section we will create a minimal Next JS page with 4 buttons:
- The first button will be used to connect a wallet to the app.
- The second button will be used to initialize the SDK using
nexus-core
. - The third button will be used to fetch the unified balances using the Nexus SDK.
- The fourth button will de-initialize the SDK using the
deinit()
function.
Set up a basic Next JS project
- Navigate into a directory of your choice and create a new Next JS project at it’s root:
pnpm create next-app@latest . --ts --eslint --app --src-dir
- Install the
nexus-core
package:
pnpm add @avail-project/nexus-core@0.0.3-beta.0
- Update the
src/app/page.tsx
file to the following:
export default function Home() {
return <div>Hello Nexus!</div>;
}
- Run a dev server using:
pnpm dev
You should now have a bare bones Next JS project running in your browser.
Let us now get down to business!!!
Set up an instance of the Nexus SDK
We will set up a single instance of the Nexus SDK and use it across the app. This will help keep the code clean and make it easier to understand the flow of the app.
- Create a file at
src/lib/nexus.ts
and add the following code:
import { NexusSDK } from '@avail-project/nexus-core';
export const sdk = new NexusSDK({ network: 'testnet'});
This initializes the Nexus SDK with the testnet
chains.
If this param is not provided, the SDK will default to mainnet
.
You can check out a complete list of the supported networks here.
- Now fill the page with the following helper functions:
// Thin wrapper that calls sdk.isInitialized() from the SDK
export function isInitialized() {
return sdk.isInitialized();
}
export async function initializeWithProvider(provider: any) {
if (!provider) throw new Error('No EIP-1193 provider (e.g., MetaMask) found');
//If the SDK is already initialized, return
if (sdk.isInitialized()) return;
//If the SDK is not initialized, initialize it with the provider passed as a parameter
await sdk.initialize(provider);
}
export async function deinit() {
//If the SDK is not initialized, return
if (!sdk.isInitialized()) return;
//If the SDK is initialized, de-initialize it
await sdk.deinit();
}
export async function getUnifiedBalances() {
//Get the unified balances from the SDK
return await sdk.getUnifiedBalances();
}
Let’s quickly go over the role of each function:
isInitialized()
: This thin wrapper callssdk.isInitialized()
from the Nexus SDK to query and return the initialization status of the SDK.initializeWithProvider(provider: any)
: This function checks if the SDK is already initialized and if not, it initializes it with the provider passed as a parameter.
This function must be called AFTER a wallet has been connected. Otherwise, the SDK will throw an error.
deinit()
: This function checks if the SDK is initialized and if so, it de-initializes it.getUnifiedBalances()
: This function callssdk.getUnifiedBalances()
from the Nexus SDK to fetch the unified balance of the user.
Set up the buttons
Create four new files in the src/components
directory:
connect-button.tsx
This component will be used to connect a EIP-1193
compatible wallet to the app.
'use client';
export default function ConnectButton({ className }: { className?: string }) {
const onClick = async () => {
const eth = (window as any)?.ethereum;
if (!eth) return alert('Install an EIP-1193 wallet (e.g., MetaMask)');
await eth.request?.({ method: 'eth_requestAccounts' });
alert('Wallet already connected');
};
return <button className={className} onClick={onClick}>Connect Wallet</button>;
}
init-button.tsx
This component will be used to initialize the SDK using nexus-core
.
'use client';
import { initializeWithProvider, isInitialized } from '../lib/nexus';
export default function InitButton({
className,
onReady,
}: { className?: string; onReady?: () => void }) {
const onClick = async () => {
const eth = (window as any)?.ethereum;
try {
// We're calling our wrapper function from the lib/nexus.ts file here.
await initializeWithProvider(eth);
onReady?.();
alert('Nexus initialized');
} catch (e: any) {
alert(e?.message ?? 'Init failed');
}
};
return <button className={className} onClick={onClick} disabled={isInitialized()}>Initialize Nexus</button>;
}
fetch-unified-balance-button.tsx
This component will be used to fetch the unified balances using the Nexus SDK.
'use client';
import { getUnifiedBalances, isInitialized } from '../lib/nexus';
export default function FetchUnifiedBalanceButton({
className,
onResult,
}: { className?: string; onResult?: (r: any) => void }) {
const onClick = async () => {
if (!isInitialized()) return alert('Initialize first');
const res = await getUnifiedBalances();
onResult?.(res);
console.log(res);
};
return <button className={className} onClick={onClick} disabled={!isInitialized()}>Fetch Unified Balances</button>;
}
de-init-button.tsx
This component will be used to de-initialize the SDK using the deinit()
function.
'use client';
import { deinit, isInitialized } from '../lib/nexus';
export default function DeinitButton({
className,
onDone,
}: { className?: string; onDone?: () => void }) {
const onClick = async () => {
await deinit();
onDone?.();
alert('Nexus de-initialized');
};
return <button className={className} onClick={onClick} disabled={!isInitialized()}>De-initialize</button>;
}
Set up the Landing Page
Update the src/app/page.tsx
file to the following:
'use client';
import { useState } from 'react';
import ConnectButton from '@/components/connect-button';
import InitButton from '@/components/init-button';
import FetchUnifiedBalanceButton from '@/components/fetch-unified-balance-button';
import DeinitButton from '@/components/de-init-button';
import { isInitialized } from '@/lib/nexus';
export default function Page() {
const [initialized, setInitialized] = useState(isInitialized());
const [balances, setBalances] = useState<any>(null);
const btn =
'px-4 py-2 rounded-md bg-blue-600 text-white hover:bg-blue-700 ' +
'disabled:opacity-50 disabled:cursor-not-allowed';
return (
<main className="min-h-screen flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<ConnectButton className={btn} />
<InitButton className={btn} onReady={() => setInitialized(true)} />
<FetchUnifiedBalanceButton className={btn} onResult={(r) => setBalances(r)} />
<DeinitButton className={btn} onDone={() => { setInitialized(false); setBalances(null); }} />
<div className="mt-2">
<b>Nexus SDK Initialization Status:</b> {initialized ? 'Initialized' : 'Not initialized'}
</div>
{balances && (
<pre className="whitespace-pre-wrap">{JSON.stringify(balances, null, 2)}</pre>
)}
</div>
</main>
);
}
sdk.getUnifiedBalances()
returns a JSON object with the balances of the user on each of the supported chains.
We’re rendering it out on the screen raw to keep the tutorial simple, but you can always format it as you please.
What’s Happening Here?
- We use the
useState
hook to manage the initialization status and balances of the SDK. - Some basic CSS is applied to the buttons to arrange them in a column.
- Some buttons are conditionally toggled based on the initialization status of the SDK.
- All in all, clicking through the buttons will allow you to initialize the SDK, fetch balances for a user, and de-initialize the SDK.
Think About What You Just Did Here!!!
In just a few lines of code, you leveraged the power of the Nexus SDK to fetch a list of tokens that the user holds across several different chains. You can now move around those tokens as you please, the possibilities are endless!
You might want to bridge one of the tokens across chains, or maybe you want to swap all existing tokens of your user spread across
different chains into ETH
on Arbitrum
.
Once you have a wallet connected and the SDK initialized, you can do all of this and more!