NERO
Getting Started

Quick Start

Create your first MPC wallet with social login using vanilla TypeScript or React

Quick Start

Build a self-custodial MPC wallet with social login.

Vanilla TypeScript

Step 1 — Create and initialize the SDK

import { NeroMpcSDK } from "@nerochain/mpc-sdk";

const sdk = new NeroMpcSDK({
  backendUrl: "https://your-api.example.com",
  apiKey: "your-project-api-key",
  chainId: 689,
});

await sdk.initialize();

The initialize() method performs three operations:

  1. Loads or generates a persistent deviceKey from storage via ClientKeyManager
  2. Attempts to restore an existing session using stored tokens
  3. If a session exists, populates the user profile and wallet information

Step 2 — Redirect to an OAuth provider

const { url } = await sdk.getOAuthUrl("google", window.location.href);
window.location.href = url;

The getOAuthUrl() method returns the authorization URL for the specified provider ("google", "apple", "github", etc.).

Step 3 — Handle the OAuth callback

After the provider redirects back, parse the code and state query parameters and call:

const { user, requiresDKG } = await sdk.handleOAuthCallback(
  "google",
  code,
  state
);

This method exchanges the code for tokens, authenticates the session, and returns requiresDKG: true if the user needs to generate a new MPC wallet.

Step 4 — Generate a wallet (first login only)

if (requiresDKG) {
  const walletInfo = await sdk.generateWallet();
  console.log(walletInfo.eoaAddress); // e.g. "0xAbc..."
}

generateWallet() initiates the Distributed Key Generation (DKG) process. For the default dkls protocol, it triggers DKLSClient.executeKeygen().

Step 5 — Sign a message

const signature = await sdk.signMessage("Hello NERO");
// returns a hex string like "0x3d48..."

signMessage() triggers the threshold signature protocol, applying the EIP-191 prefix and coordinating between client and backend shares to produce a valid ECDSA signature without reconstructing the private key.

React Quick Start

The React integration layer wraps NeroMpcSDK in a context provider.

Provider setup

import { NeroMpcAuthProvider } from "@nerochain/mpc-sdk/react";

function App() {
  return (
    <NeroMpcAuthProvider
      config={{
        backendUrl: "https://your-api.example.com",
        chainId: 689,
      }}
    >
      <Wallet />
    </NeroMpcAuthProvider>
  );
}

Authentication and wallet hooks

import {
  useNeroConnect,
  useNeroWallet,
  useNeroUser,
} from "@nerochain/mpc-sdk/react";

function Wallet() {
  const { connect, isConnecting } = useNeroConnect();
  const { user } = useNeroUser();
  const { wallet, signMessage } = useNeroWallet();

  if (!user) {
    return <button onClick={() => connect("google")}>Login</button>;
  }

  return (
    <div>
      <p>Address: {wallet?.eoaAddress}</p>
      <button onClick={() => signMessage("Test message")}>Sign</button>
    </div>
  );
}

Key Concepts

DKLS vs Pedersen protocols:

ProtocolModeKey PropertyUse Case
DKLS (default)2-party threshold ECDSAMultiplicative secret sharingDirect EOA wallet, efficient signing
Pedersen DKGDistributed key generationVerifiable secret sharingSmart account (ERC-4337), multi-party

Device key: A persistent identifier unique to each browser instance, used for encrypting stored tokens and key shares.

requiresDKG flag: Indicates whether the user must generate a new wallet before signing. Returned by login methods — check this flag to determine if generateWallet() should be called.

NeroMpcSDK Class Reference

Constructor

new NeroMpcSDK(config: SDKConfig)

Factory Function

createNeroSDK(config: SDKConfig): NeroMpcSDK

Functionally identical to new NeroMpcSDK(config).

Public Properties

PropertyTypeDescription
isAuthenticatedbooleantrue when user and valid tokens exist
hasWalletbooleanProtocol-aware check (DKLS: _dklsWalletAddress !== null, Pedersen: _wallet !== null)
connectedbooleanEIP-1193 provider connection status
statusConnectionStatus"disconnected", "connecting", "connected", or "reconnecting"
userUser | nullCurrent authenticated user
walletSmartWallet | nullWallet instance (Pedersen only)
chainIdnumberActive chain ID; mutable via switchChain()
providerNeroProvider | nullEIP-1193 provider instance
stateNeroSDKStateSnapshot containing all key state properties

Event System

Register listeners for SDK lifecycle events:

sdk.on("initialized", () => console.log("SDK ready"));
sdk.on("login", (user) => console.log("Logged in:", user));
sdk.on("connected", () => console.log("Provider connected"));
EventWhen it fires
"initialized"After initialization completes
"login"After successful authentication
"logout"After session is cleared
"connected"When EIP-1193 provider is ready
"disconnected"When provider disconnects

Methods: on(event, listener), off(event, listener), once(event, listener)

Error Handling

The SDK uses a structured error hierarchy:

SDKError (base)
├── AuthError
├── WalletError
├── ProtocolError
├── NetworkError
└── SigningError

Common Error Codes

CodeDescription
NOT_AUTHENTICATEDUser not logged in
RECOVERY_REQUIREDClient key share missing
SIGNING_SESSION_CONFLICTAnother signing session active
DKG_FAILEDDistributed Key Generation failed
TOKEN_EXPIREDAccess token expired
NETWORK_ERRORCommunication failure

Error Handling Pattern

try {
  await sdk.signMessage("test");
} catch (error) {
  if (error.code === "NOT_AUTHENTICATED") {
    // Redirect to login
  } else if (error.code === "RECOVERY_REQUIRED") {
    // Initiate recovery flow
  }
}

On this page