npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@octwa/sdk

v1.1.1

Published

Official TypeScript SDK for integrating dApps with OctWa Wallet Extension. Implements capability-based authorization with full HFHE support.

Readme

Octra Web Wallet SDK

Version: 2.0.0
License: MIT
Status: Production Ready ✅

The official TypeScript SDK for integrating with the Octra blockchain through the OctWa wallet extension. Implements a capability-based authorization model with full support for HFHE (Homomorphic Fully Encrypted) transactions.


Table of Contents


Overview

The Octra SDK provides a stateless, deterministic transaction builder for dApps to interact with the Octra blockchain. It follows a strict security model where:

  • SDK: Builds transactions deterministically (NO signing, NO private keys)
  • Wallet: Final authority for signing and transaction submission
  • Network: Executes transactions with HFHE encryption support

Key Features

Capability-Based Authorization - Fine-grained permission model
HFHE Support - Fully encrypted transaction execution
Deterministic Serialization - Canonical transaction building
Domain Separation - Prevents signature replay attacks
Signing Mutex - Prevents race conditions and double-send
Type-Safe - Full TypeScript support with comprehensive types
Event System - Real-time connection and capability events
Gas Estimation - Built-in gas and compute cost estimation
🚫 Intent-Based Swaps - Cross-chain swap support (currently disabled, under development)


Architecture

┌─────────┐      ┌─────────┐      ┌────────────┐      ┌──────────────┐
│  DApp   │─────▶│   SDK   │─────▶│   Wallet   │─────▶│ Octra Network│
│         │      │         │      │ (Extension)│      │              │
└─────────┘      └─────────┘      └────────────┘      └──────────────┘
                                         │
                                         │ Private Keys
                                         │ Signing
                                         │ Nonce Validation
                                         ▼
                                  Final Authority

Trust Boundaries

  1. DApp Layer: User interface and business logic
  2. SDK Layer: Stateless transaction builder (this package)
  3. Wallet Layer: Private key custody and signing
  4. Network Layer: Transaction execution and state management

Installation

npm install @octra/sdk

Or with yarn:

yarn add @octra/sdk

Or with pnpm:

pnpm add @octra/sdk

Requirements

  • Node.js >= 16
  • TypeScript >= 4.5 (optional, but recommended)
  • OctWa Wallet Extension installed in browser

Quick Start

1. Initialize SDK

import { OctraSDK } from '@octra/sdk';

// Initialize SDK (detects wallet extension)
const sdk = await OctraSDK.init({
  timeout: 3000, // Wait up to 3s for extension
});

// Check if wallet is installed
if (!sdk.isInstalled()) {
  console.error('Please install OctWa wallet extension');
  return;
}

2. Connect to Wallet

// Request connection to a Circle
const connection = await sdk.connect({
  circle: 'my-circle-id',
  appName: 'My DApp',
  appIcon: 'https://mydapp.com/icon.png',
});

console.log('Connected:', connection.walletPubKey);
console.log('EVM Address:', connection.evmAddress);
console.log('Network:', connection.network);

3. Request Capability

// Request permission to call specific methods
const capability = await sdk.requestCapability({
  circle: 'my-circle-id',
  methods: ['get_balance', 'send_transaction'],
  scope: 'write',
  encrypted: false,
  ttlSeconds: 3600, // 1 hour
});

console.log('Capability granted:', capability.id);

4. Invoke Methods

// Get balance
const result = await sdk.invoke({
  capabilityId: capability.id,
  method: 'get_balance',
});

// Decode response
import { decodeBalanceResponse } from '@octra/sdk';
const balance = decodeBalanceResponse(result);
console.log('OCT Balance:', balance.octBalance);
console.log('ETH Balance:', balance.ethBalance);

Core Concepts

Capabilities

Capabilities are cryptographically signed permissions that grant your dApp access to specific methods. They are:

  • Scoped: Limited to specific methods
  • Time-bound: Have expiration times
  • Origin-bound: Tied to your dApp's origin
  • Revocable: Can be revoked by user at any time

Capability Scopes:

  • read: Read-only operations (e.g., get_balance)
  • write: State-changing operations (e.g., send_transaction)
  • compute: HFHE computation operations

Invocations

Invocations are signed method calls using a capability. Each invocation:

  • Uses a monotonically increasing nonce (replay protection)
  • Includes domain separation (prevents signature replay)
  • Is validated by the wallet before execution
  • Can include encrypted payloads (HFHE)

Sessions

Sessions represent the connection state between your dApp and the wallet:

const session = sdk.getSessionState();
console.log('Connected:', session.connected);
console.log('Circle:', session.circle);
console.log('Active Capabilities:', session.activeCapabilities.length);

API Reference

OctraSDK Class

Static Methods

init(options?: InitOptions): Promise<OctraSDK>

Initialize the SDK and detect wallet extension.

const sdk = await OctraSDK.init({
  timeout: 3000, // Detection timeout in ms
  autoCleanupExpired: true, // Auto-remove expired capabilities
  skipSignatureVerification: false, // For testing only
});

Instance Methods

isInstalled(): boolean

Check if wallet extension is installed.

if (!sdk.isInstalled()) {
  alert('Please install OctWa wallet');
}
connect(request: ConnectRequest): Promise<Connection>

Request connection to a Circle.

const connection = await sdk.connect({
  circle: 'circle-id',
  appName: 'My DApp',
  appIcon: 'https://example.com/icon.png',
  appOrigin: window.location.origin, // Auto-detected
  requestedCapabilities: [ // Optional: request capabilities immediately
    {
      methods: ['get_balance'],
      scope: 'read',
      encrypted: false,
    }
  ],
});

Returns:

interface Connection {
  circle: string;
  sessionId: string;
  walletPubKey: string;
  evmAddress?: string;
  network: 'testnet' | 'mainnet';
  epoch: number;
  branchId: string;
}
disconnect(): Promise<void>

Disconnect from wallet and clear all capabilities.

await sdk.disconnect();
requestCapability(request: CapabilityRequest): Promise<Capability>

Request a new capability from the user.

const capability = await sdk.requestCapability({
  circle: 'circle-id',
  methods: ['get_balance', 'send_transaction'],
  scope: 'write',
  encrypted: false,
  ttlSeconds: 3600, // Optional: default 1 hour
  branchId: 'main', // Optional: specific branch
});

Returns:

interface Capability {
  id: string;
  version: 2;
  circle: string;
  methods: readonly string[];
  scope: 'read' | 'write' | 'compute';
  encrypted: boolean;
  appOrigin: string;
  branchId: string;
  epoch: number;
  issuedAt: number;
  expiresAt: number;
  nonceBase: number;
  walletPubKey: string;
  signature: string;
  state: 'ACTIVE' | 'EXPIRED' | 'REVOKED';
  lastNonce: number;
}
renewCapability(capabilityId: string): Promise<Capability>

Renew an existing capability (extends expiration).

const renewed = await sdk.renewCapability(capability.id);
revokeCapability(capabilityId: string): Promise<void>

Revoke a capability (user can also revoke from wallet UI).

await sdk.revokeCapability(capability.id);
listCapabilities(): Promise<Capability[]>

List all active capabilities for current origin.

const capabilities = await sdk.listCapabilities();
invoke(request: InvocationRequest): Promise<InvocationResult>

Invoke a method using a capability.

const result = await sdk.invoke({
  capabilityId: capability.id,
  method: 'get_balance',
  payload: new TextEncoder().encode(JSON.stringify({ /* params */ })),
  branchId: 'main', // Optional: override branch
});

Returns:

interface InvocationResult {
  success: boolean;
  data?: Uint8Array | EncryptedPayload;
  error?: string;
  branchProofHash?: string;
  merkleRoot?: string;
  epochTag?: number;
}
invokeCompute(request: ComputeRequest): Promise<ComputeResult>

Execute HFHE computation.

const result = await sdk.invokeCompute({
  circleId: 'circle-id',
  capabilityId: capability.id,
  branchId: 'main',
  circuitId: 'my-circuit',
  encryptedInput: {
    scheme: 'HFHE',
    data: encryptedData,
    associatedData: 'metadata',
  },
  computeProfile: {
    gateCount: 1000,
    vectorSize: 256,
    depth: 10,
    expectedBootstrap: 2,
  },
  gasLimit: 1000000,
});
estimatePlainTx(payload: unknown): Promise<GasEstimate>

Estimate gas for plain transaction.

const estimate = await sdk.estimatePlainTx({ amount: 100 });
console.log('Gas units:', estimate.gasUnits);
console.log('Token cost:', estimate.tokenCost);
estimateEncryptedTx(payload: EncryptedPayload): Promise<GasEstimate>

Estimate gas for encrypted transaction.

const estimate = await sdk.estimateEncryptedTx(encryptedPayload);
estimateComputeCost(profile: ComputeProfile): Promise<GasEstimate>

Estimate cost for HFHE computation.

const estimate = await sdk.estimateComputeCost({
  gateCount: 1000,
  vectorSize: 256,
  depth: 10,
  expectedBootstrap: 2,
});
signMessage(message: string): Promise<string>

Request user to sign an arbitrary message.

const signature = await sdk.signMessage('Hello, Octra!');
getSessionState(): SessionState

Get current session state.

const state = sdk.getSessionState();
console.log('Connected:', state.connected);
console.log('Active capabilities:', state.activeCapabilities);
on<E>(event: EventName, callback: EventCallback<E>): () => void

Subscribe to events. Returns unsubscribe function.

const unsubscribe = sdk.on('connect', ({ connection }) => {
  console.log('Connected to:', connection.circle);
});

// Later: unsubscribe()

Events:

  • extensionReady: Wallet extension detected
  • connect: Connected to wallet
  • disconnect: Disconnected from wallet
  • capabilityGranted: New capability granted
  • capabilityExpired: Capability expired
  • capabilityRevoked: Capability revoked
  • branchChanged: Branch changed
  • epochChanged: Epoch changed

Security

Canonical Serialization

All transactions use deterministic canonical serialization:

import { canonicalize, canonicalizeCapability } from '@octra/sdk';

// Canonicalize any object
const canonical = canonicalize({ b: 2, a: 1 });
// Result: '{"a":1,"b":2}' (keys sorted)

// Canonicalize capability
const capCanonical = canonicalizeCapability(capabilityPayload);

Rules:

  • Keys sorted lexicographically
  • No whitespace
  • Deterministic number formatting
  • Uint8Array → hex with '0x' prefix

Domain Separation

Prevents signature replay attacks:

import { 
  OCTRA_CAPABILITY_PREFIX,
  OCTRA_INVOCATION_PREFIX,
  hashCapabilityWithDomain 
} from '@octra/sdk';

// Capability signing includes domain prefix
const hash = hashCapabilityWithDomain(payload);
// Internally: hash(OCTRA_CAPABILITY_PREFIX + canonical)

Signing Mutex

Automatic protection against race conditions:

// These will execute sequentially, not in parallel
const [result1, result2] = await Promise.all([
  sdk.invoke({ capabilityId, method: 'method1' }),
  sdk.invoke({ capabilityId, method: 'method2' }),
]);
// result1.nonce = 1, result2.nonce = 2 (guaranteed order)

HFHE Encrypted Payloads

Encrypted payloads are treated as opaque blobs:

import { hashPayload } from '@octra/sdk';

// ✅ CORRECT: Hash without inspecting
const hash = hashPayload(encryptedPayload);

// ❌ WRONG: Don't inspect ciphertext
const data = JSON.parse(encryptedPayload.data); // Never do this!

Nonce Management

SDK provides nonces for ordering, wallet validates:

// SDK manages nonce locally
const nonce = nonceManager.getNextNonce(capabilityId);

// On error, rollback
catch (error) {
  nonceManager.resetNonce(capabilityId, nonce - 1);
}

// Wallet is final authority and validates nonce

Advanced Usage

Intent-Based Swaps

import { IntentsClient } from '@octra/sdk';

// Create intents client
const intents = new IntentsClient(sdk, 'https://api.octra.network');
intents.setCapability(capability);

// Get quote
const quote = await intents.getQuote(100); // 100 OCT

// Create intent
const intent = await intents.createIntent(
  quote,
  '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', // Target ETH address
  50 // 0.5% slippage
);

// Sign and submit
const signResult = await intents.signIntent(intent);
const submitResult = await intents.submitIntent(signResult.txHash);

// Poll for fulfillment
const status = await intents.waitForFulfillment(submitResult.intentId, {
  timeoutMs: 5 * 60 * 1000, // 5 minutes
  pollIntervalMs: 3000, // Check every 3s
});

console.log('Swap completed:', status.ethTxHash);

Response Decoding

import { decodeResponseData, decodeBalanceResponse } from '@octra/sdk';

// Generic decoding
const result = await sdk.invoke({ capabilityId, method: 'custom_method' });
const data = decodeResponseData<MyType>(result);

// Balance-specific decoding
const balanceResult = await sdk.invoke({ capabilityId, method: 'get_balance' });
const balance = decodeBalanceResponse(balanceResult);

Cryptographic Utilities

import {
  sha256,
  hexToBytes,
  bytesToHex,
  verifyEd25519Signature,
  verifyCapabilitySignature,
} from '@octra/sdk';

// SHA-256 hashing
const hash = await sha256(data);

// Hex conversion
const bytes = hexToBytes('0x1234abcd');
const hex = bytesToHex(bytes);

// Signature verification
const isValid = await verifyEd25519Signature(
  signature,
  message,
  publicKey
);

// Capability verification
const isValidCap = await verifyCapabilitySignature(capability);

Error Handling

All errors extend OctraError with structured information:

import {
  OctraError,
  NotInstalledError,
  NotConnectedError,
  UserRejectedError,
  ValidationError,
  CapabilityError,
} from '@octra/sdk';

try {
  await sdk.invoke(request);
} catch (error) {
  if (error instanceof UserRejectedError) {
    // User cancelled - don't show error
    console.log('User cancelled');
  } else if (error instanceof NotConnectedError) {
    // Need to connect first
    await sdk.connect({ circle: 'my-circle' });
  } else if (error instanceof CapabilityError) {
    // Capability issue - might need to renew
    console.error('Capability error:', error.message);
  } else if (error instanceof OctraError) {
    // Generic Octra error
    console.error('Error code:', error.code);
    console.error('Details:', error.details);
  }
}

Error Codes:

  • NOT_INSTALLED: Wallet extension not installed
  • NOT_CONNECTED: Not connected to wallet
  • USER_REJECTED: User rejected the request
  • TIMEOUT: Operation timed out
  • VALIDATION_ERROR: Input validation failed
  • CAPABILITY_ERROR: Capability issue
  • SCOPE_VIOLATION: Method not allowed by capability
  • SIGNATURE_INVALID: Invalid signature
  • CAPABILITY_EXPIRED: Capability expired
  • CAPABILITY_REVOKED: Capability revoked
  • ORIGIN_MISMATCH: Origin mismatch
  • BRANCH_MISMATCH: Branch mismatch
  • EPOCH_MISMATCH: Epoch mismatch
  • NONCE_VIOLATION: Nonce violation
  • DOMAIN_SEPARATION_ERROR: Domain separation error

Testing

Unit Tests

npm test

Integration Tests

npm run test:integration

Test with Mock Wallet

import { OctraSDK } from '@octra/sdk';

const sdk = await OctraSDK.init({
  skipSignatureVerification: true, // For testing only!
});

Migration Guide

From v1 to v2

Breaking Changes:

  1. Error Structure: Errors now include code, layer, retryable
  2. Domain Separation: Signatures include domain prefixes
  3. Canonical Serialization: All hashing uses canonical format

Migration Steps:

// v1
try {
  await sdk.invoke(request);
} catch (error) {
  alert(error.message);
}

// v2
try {
  await sdk.invoke(request);
} catch (error) {
  if (error.code === 'USER_REJECTED') {
    return; // Don't show error
  }
  
  if (error.retryable) {
    // Show retry button
  } else {
    alert(error.message);
  }
}

Compatibility:

  • ✅ v1 capabilities still work
  • ✅ v1 API unchanged
  • ✅ New features are additive

File Structure

packages/sdk/
├── src/
│   ├── canonical.ts           # Canonical serialization
│   ├── capability-manager.ts  # Capability management
│   ├── capability-service.ts  # Capability validation
│   ├── compute-service.ts     # HFHE compute operations
│   ├── crypto.ts              # Cryptographic utilities
│   ├── errors.ts              # Error classes
│   ├── gas-service.ts         # Gas estimation
│   ├── index.ts               # Public API exports
│   ├── intents.ts             # Intent-based swaps
│   ├── nonce-manager.ts       # Nonce management
│   ├── response-utils.ts      # Response decoding
│   ├── sdk.ts                 # Main SDK class
│   ├── session-manager.ts     # Session management
│   ├── types.ts               # TypeScript types
│   └── utils.ts               # Utility functions
├── tests/
│   ├── crypto.test.ts         # Crypto tests
│   └── sdk.test.ts            # SDK tests
├── dist/                      # Compiled output
├── package.json
├── tsconfig.json
├── vitest.config.ts
└── README.md                  # This file

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new features
  4. Ensure all tests pass
  5. Submit a pull request

License

MIT License - see LICENSE file for details


Support

  • Documentation: https://docs.octra.network
  • GitHub: https://github.com/octra/octwa
  • Discord: https://discord.gg/octra
  • Email: [email protected]

Security

For security issues, please email: [email protected]

Do NOT open public issues for security vulnerabilities.


Built with ❤️ by the Octra Team