npm.io
0.1.1 • Published 7h ago

@inferenco/nova-wallet-adapter

Licence
Apache-2.0
Version
0.1.1
Deps
6
Size
761 kB
Vulns
0
Weekly
0

Nova Wallet Adapter

npm version npm downloads license TypeScript Module formats version

Wallet adapter for connecting Cedra dApps to Nova Desk and Nova Wallet.
Supports the AIP-62 wallet-standard and plugin-style integration.


Overview

This adapter allows Cedra dApps to connect to two Nova products:

  • Nova Desk — Desktop application. The adapter connects directly to Nova Desk's local HTTP bridge at localhost:21984. No external services required.
  • Nova Wallet — Mobile wallet app. The adapter connects through nova-service, a hosted relay that brokers end-to-end encrypted communication between the dApp and the wallet via deeplinks.

Both connections are handled transparently — the adapter detects the environment and uses the right transport automatically.

Features

  • Nova Desk integration — Direct local HTTP bridge to the Nova Desk desktop application
  • Nova Wallet integration — End-to-end encrypted relay via nova-service (X25519 + XChaCha20-Poly1305)
  • Dual dApp integration — Plugin adapter (NovaWallet) and AIP-62 wallet-standard (registerNovaWallet)
  • Injected provider — Auto-detects window.inferenco, window.nova, and branded aliases
  • Deeplinksinferenco:// URI scheme for wallet handoff on desktop and mobile
  • Session persistence — Reconnect without re-approval across page reloads
  • Zero config — Works out of the box with sensible defaults, fully configurable when needed

Installation

npm install @inferenco/nova-wallet-adapter
yarn add @inferenco/nova-wallet-adapter
pnpm add @inferenco/nova-wallet-adapter

Quick Start

The simplest way to integrate — auto-register Nova as a wallet-standard wallet:

// Side-effect import — registers Nova wallet automatically
import "@inferenco/nova-wallet-adapter/auto-register";

Or register manually with options:

import { registerNovaWallet } from "@inferenco/nova-wallet-adapter/aip62";

registerNovaWallet({
  forceRegistration: true,  // Register even without injected provider
});
Plugin Adapter

For dApps using plugin-style adapters:

import { NovaWallet } from "@inferenco/nova-wallet-adapter";

const wallet = new NovaWallet();

// Connect
const account = await wallet.connect();
console.log(account.address);

// Sign a message
const response = await wallet.signMessage({
  message: "Hello Nova!",
  nonce: "unique-nonce-123",
});

// Sign and submit a transaction
const result = await wallet.signAndSubmitTransaction({
  data: {
    function: "0x1::coin::transfer",
    typeArguments: ["0x1::aptos_coin::AptosCoin"],
    functionArguments: ["0xrecipient", 1000],
  },
});

// Disconnect
await wallet.disconnect();
Using NovaClient Directly

For full control over the connection lifecycle:

import { NovaClient } from "@inferenco/nova-wallet-adapter";

const client = new NovaClient({
  bridgeBaseUrl: "http://127.0.0.1:21984",
  detectAliases: true,
});

const { account, network } = await client.connect();

const signed = await client.signTransaction(rawTransaction);
const result = await client.signAndSubmitTransaction(transactionPayload);
WalletCore Resume Helper

If your dApp uses Cedra WalletCore, call the resume helper during provider bootstrap:

import {
  NOVA_CONNECT_NAME,
  tryResumeNovaWalletConnection,
} from "@inferenco/nova-wallet-adapter";

await tryResumeNovaWalletConnection(walletCore);

This resumes pending mobile callback state after browser reloads and reconnects through stored sessions without app-specific bridge logic.

Architecture

The adapter provides two dApp integration surfaces backed by a shared NovaClient, which connects to Nova Desk or Nova Wallet depending on the environment:

┌─────────────────────────────────────────────────────────┐
│                     Your dApp                           │
│                                                         │
│   NovaWallet (plugin)  ─┐                               │
│                         ├──▶  NovaClient (core logic)   │
│   AIP-62 Bridge ────────┘         │                     │
└───────────────────────────────────┼─────────────────────┘
                                    │
              ┌─────────────────────┼─────────────────────┐
              ▼                     ▼                     ▼
     ┌──────────────┐     ┌──────────────┐     ┌──────────────┐
     │   Injected   │     │  Nova Desk   │     │ Nova Wallet  │
     │   Provider   │     │  (desktop)   │     │  (mobile)    │
     │              │     │              │     │              │
     │ window.nova  │     │  localhost   │     │ nova-service │
     │ window.      │     │  :21984      │     │  + deeplink  │
     │  inferenco   │     │  HTTP bridge │     │  E2E encrypt │
     └──────────────┘     └──────────────┘     └──────────────┘
How Connections Work

Desktop — Nova Desk: The adapter connects to Nova Desk's local HTTP bridge at http://127.0.0.1:21984. Requests are initiated, then polled until the user approves in the Nova Desk UI. Sessions persist across page reloads.

Mobile — Nova Wallet: The adapter creates an encrypted pairing through nova-service, then launches an inferenco:// deeplink to hand off to Nova Wallet. The user approves in the app, and the result is returned through the relay. All communication is end-to-end encrypted.

Injected provider: When a Nova extension is installed, the adapter calls it directly — no bridge or relay needed.

Connection Order
  1. Injected providerwindow.inferenco / window.nova (instant, direct)
  2. Stored session — validates and reuses a prior Nova Desk or Nova Wallet session
  3. Nova Desk bridge — local HTTP connection on desktop browsers
  4. Nova Wallet relay — encrypted relay + deeplink on mobile browsers
  5. Desktop deeplinkinferenco://login handoff when Nova Desk is not running

Nova Desk and nova-service are independent. Nova Desk works without nova-service, and Nova Wallet works without Nova Desk.

For more detail, see Architecture docs.

API Reference

NovaWallet

The plugin adapter class, compatible with plugin-style wallet consumers.

Method Returns Description
connect() Promise<AccountInfo> Connect to Nova Desk or Nova Wallet
account() Promise<AccountInfo> Get current account info
disconnect() Promise<void> Disconnect and clear session
signMessage(input) Promise<CedraSignMessageOutput> Sign an arbitrary message
signTransaction(tx, opts?) Promise<Uint8Array | { authenticator, rawTransaction?: AnyRawTransaction }> Sign a transaction without submitting
signAndSubmitTransaction(tx, opts?) Promise<CedraSignAndSubmitTransactionOutput> Sign and submit a transaction
signAndSubmitBCSTransaction(tx, opts?) Promise<CedraSignAndSubmitTransactionOutput> Sign and submit (BCS variant)
onAccountChange(cb) Promise<void> Subscribe to account changes
onNetworkChange(cb) Promise<void> Subscribe to network changes
deeplinkProvider(url?) string Generate a deeplink URL

signTransaction accepts prebuilt SDK transactions and Cedra wallet-standard v1.1 inputs, including secondarySigners and fee payer fields. When the wallet returns a signed multi-agent transaction, the adapter preserves the SDK AnyRawTransaction wrapper so secondary signer and fee payer metadata remains available for submission.

Properties:

Property Type Description
name "Nova Connect" Wallet display name
url string Wallet website URL
icon string Base64 SVG icon
readyState NovaWalletReadyState Current detection state
connecting boolean Connection in progress
connected boolean Currently connected
publicAccount NovaAccountKeys Cached public key info
network NovaNetworkInfo Current network info
registerNovaWallet(options?)

Registers Nova as an AIP-62 wallet-standard wallet. Implements all Cedra standard features:

  • cedra:connect, cedra:disconnect, cedra:account, cedra:network
  • cedra:signMessage, cedra:signTransaction, cedra:signAndSubmitTransaction
  • cedra:onAccountChange, cedra:onNetworkChange
  • cedra:openInMobileApp
NovaClient

The core client powering both adapter surfaces. Use directly for advanced control.

Method Returns Description
connect() Promise<{ account, network }> Connect to Nova Desk or Nova Wallet
disconnect() Promise<void> Disconnect and revoke session
getAccount() Promise<AccountInfo> Fetch account from provider or session
getNetwork() Promise<NetworkInfo> Fetch current network
signMessage(input) Promise<CedraSignMessageOutput> Sign message via active transport
signMessageAndVerify(input) Promise<boolean> Sign and verify locally
signTransaction(tx, opts?) Promise<NovaSignTransactionResult> Sign transaction
signAndSubmitTransaction(tx, opts?) Promise<CedraSignAndSubmitTransactionOutput> Sign and submit
hasProvider() boolean Check for injected provider
hasExternalSession() boolean Check for stored Nova Desk or Nova Wallet session

For the complete type reference, see API Reference docs.

Configuration

All options are optional with sensible defaults:

const wallet = new NovaWallet({
  // Identity & deeplinks
  deeplinkBaseUrl: "inferenco://connect?callback=",
  deeplinkScheme: "inferenco",
  websiteUrl: "https://inferenco.com/nova-desk",

  // Registration behavior
  forceRegistration: false,     // Register even without injected provider
  desktopRegistration: true,    // Register on desktop browsers
  detectAliases: true,          // Check window.cedra / window.aptos

  // Network
  networkOverride: undefined,   // Force specific network
  fullnodeUrl: undefined,       // Custom fullnode for SDK operations

  // Nova Desk (desktop bridge)
  bridgeBaseUrl: "http://127.0.0.1:21984",
  bridgeConnectTimeoutMs: 1200,
  bridgePollIntervalMs: 250,
  bridgePollTimeoutMs: 120000,

  // Nova Wallet (mobile relay via nova-service)
  relayBaseUrl: "https://nova-service-....run.app",
  websocketBaseUrl: "wss://nova-service-....run.app/v1/ws",
  mobilePollIntervalMs: 1000,
  mobileRequestTimeoutMs: 180000,
  mobileSocketTimeoutMs: 15000,
});

See Configuration docs for detailed descriptions of each option.

Error Handling

All adapter errors are instances of NovaAdapterError with a typed error code:

import { NovaAdapterError, NovaErrorCode } from "@inferenco/nova-wallet-adapter";

try {
  await wallet.connect();
} catch (error) {
  if (error instanceof NovaAdapterError) {
    switch (error.code) {
      case NovaErrorCode.UserRejected:
        console.log("User rejected the request");
        break;
      case NovaErrorCode.ConnectionTimeout:
        console.log("Connection timed out");
        break;
      case NovaErrorCode.NotInstalled:
        console.log("Nova Wallet not found");
        break;
    }
  }
}
Error Code Value Description
UserRejected USER_REJECTED User declined the request
Unauthorized UNAUTHORIZED Session expired or invalid
Unsupported UNSUPPORTED Operation not supported by provider
NotInstalled NOT_INSTALLED No provider or bridge found
ConnectionTimeout CONNECTION_TIMEOUT Bridge/relay connection timed out
InvalidParams INVALID_PARAMS Invalid parameters provided
InvalidNetwork INVALID_NETWORK Network mismatch or unavailable
InternalError INTERNAL_ERROR Unexpected internal error

Provider Detection

The adapter detects Nova providers in this priority order:

  1. window.inferenco — primary namespace
  2. window.nova — secondary namespace
  3. window.cedra — only if isNovaWallet === true (branded)
  4. window.aptos — only if isNovaWallet === true (branded)

Unbranded providers on window.cedra / window.aptos are never wrapped. Alias detection can be disabled with detectAliases: false.

Session Management

Sessions are persisted in localStorage under the key inferenco:nova-session and automatically validated on reconnect:

  • Nova Desk sessions are validated against the bridge's /session/{id} endpoint
  • Nova Wallet sessions trust the stored encrypted credentials
  • Invalid or expired sessions are automatically cleared, triggering a fresh connection flow

Nova Wallet Relay Security

Communication between the dApp and Nova Wallet through nova-service is end-to-end encrypted:

Layer Algorithm Purpose
Key exchange X25519 (ECDH) Derive shared secret between dApp and wallet
Key derivation HKDF-SHA256 Deterministic key from shared secret with "nova-connect-relay" info
Encryption XChaCha20-Poly1305 Authenticated encryption of all request/response payloads
Nonce 24 random bytes Per-message nonce prevents replay attacks

The relay server (nova-service) never sees plaintext request or response data.

Exports

The package ships three entry points:

Entry Point Import Path Contents
Main @inferenco/nova-wallet-adapter NovaWallet, NovaClient, types, utilities, errors
AIP-62 @inferenco/nova-wallet-adapter/aip62 createNovaAIP62Wallet, registerNovaWallet
Auto-register @inferenco/nova-wallet-adapter/auto-register Side-effect registration (import-only)

Both ESM and CommonJS builds are included with full TypeScript declarations.

Nova Desk Bridge API

When Nova Desk is running locally, the adapter communicates via HTTP:

Endpoint Method Description
/connect GET Initiate connection request
/sign-message POST Sign message request
/sign-transaction POST Sign transaction request
/transaction POST Sign and submit transaction
/request/{requestId} GET Poll for request status
/session/{sessionId} GET Validate existing session
/connection DELETE Revoke connection
/session/{sessionId} DELETE Revoke session

All operations use a poll-based flow: initiate a request, receive a requestId, then poll until the user approves or rejects in Nova Desk.

Development

# Install dependencies
npm install

# Build (ESM + CJS + declarations)
npm run build

# Run tests
npm test

# Watch tests
npm run test:watch

# Type check
npm run typecheck

Documentation

Document Description
Architecture Transport mechanisms, connection flows, and system design
API Reference Complete type and method documentation
Configuration All options with defaults and examples
Mobile Relay Protocol Nova Wallet end-to-end encrypted communication
Changelog Version history and release notes

Dependencies

Package Purpose
@cedra-labs/ts-sdk Transaction building, network utilities, SDK operations
@cedra-labs/wallet-standard AIP-62 wallet-standard types and registration
@noble/curves X25519 ECDH key exchange (Nova Wallet relay)
@noble/hashes SHA256, HKDF key derivation (Nova Wallet relay)
@noble/ciphers XChaCha20-Poly1305 authenticated encryption (Nova Wallet relay)
eventemitter3 Event emission for account/network change subscriptions

License

Apache-2.0

Keywords