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:
- Loads or generates a persistent
deviceKeyfrom storage viaClientKeyManager - Attempts to restore an existing session using stored tokens
- 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:
| Protocol | Mode | Key Property | Use Case |
|---|---|---|---|
| DKLS (default) | 2-party threshold ECDSA | Multiplicative secret sharing | Direct EOA wallet, efficient signing |
| Pedersen DKG | Distributed key generation | Verifiable secret sharing | Smart 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): NeroMpcSDKFunctionally identical to new NeroMpcSDK(config).
Public Properties
| Property | Type | Description |
|---|---|---|
isAuthenticated | boolean | true when user and valid tokens exist |
hasWallet | boolean | Protocol-aware check (DKLS: _dklsWalletAddress !== null, Pedersen: _wallet !== null) |
connected | boolean | EIP-1193 provider connection status |
status | ConnectionStatus | "disconnected", "connecting", "connected", or "reconnecting" |
user | User | null | Current authenticated user |
wallet | SmartWallet | null | Wallet instance (Pedersen only) |
chainId | number | Active chain ID; mutable via switchChain() |
provider | NeroProvider | null | EIP-1193 provider instance |
state | NeroSDKState | Snapshot 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"));| Event | When 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
└── SigningErrorCommon Error Codes
| Code | Description |
|---|---|
NOT_AUTHENTICATED | User not logged in |
RECOVERY_REQUIRED | Client key share missing |
SIGNING_SESSION_CONFLICT | Another signing session active |
DKG_FAILED | Distributed Key Generation failed |
TOKEN_EXPIRED | Access token expired |
NETWORK_ERROR | Communication 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
}
}