
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
Official TypeScript SDK for integrating dApps with OctWa Wallet Extension. Implements capability-based authorization with full HFHE support.
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.
The Octra SDK provides a stateless, deterministic transaction builder for dApps to interact with the Octra blockchain. It follows a strict security model where:
✅ 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)
┌─────────┐ ┌─────────┐ ┌────────────┐ ┌──────────────┐
│ DApp │─────▶│ SDK │─────▶│ Wallet │─────▶│ Octra Network│
│ │ │ │ │ (Extension)│ │ │
└─────────┘ └─────────┘ └────────────┘ └──────────────┘
│
│ Private Keys
│ Signing
│ Nonce Validation
▼
Final Authority
npm install @octra/sdk
Or with yarn:
yarn add @octra/sdk
Or with pnpm:
pnpm add @octra/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;
}
// 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);
// 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);
// 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);
Capabilities are cryptographically signed permissions that grant your dApp access to specific methods. They are:
Capability Scopes:
read: Read-only operations (e.g., get_balance)write: State-changing operations (e.g., send_transaction)compute: HFHE computation operationsInvocations are signed method calls using a capability. Each invocation:
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);
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
});
isInstalled(): booleanCheck 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(): SessionStateGet 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>): () => voidSubscribe to events. Returns unsubscribe function.
const unsubscribe = sdk.on('connect', ({ connection }) => {
console.log('Connected to:', connection.circle);
});
// Later: unsubscribe()
Events:
extensionReady: Wallet extension detectedconnect: Connected to walletdisconnect: Disconnected from walletcapabilityGranted: New capability grantedcapabilityExpired: Capability expiredcapabilityRevoked: Capability revokedbranchChanged: Branch changedepochChanged: Epoch changedAll 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:
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)
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)
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!
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
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);
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);
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);
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 installedNOT_CONNECTED: Not connected to walletUSER_REJECTED: User rejected the requestTIMEOUT: Operation timed outVALIDATION_ERROR: Input validation failedCAPABILITY_ERROR: Capability issueSCOPE_VIOLATION: Method not allowed by capabilitySIGNATURE_INVALID: Invalid signatureCAPABILITY_EXPIRED: Capability expiredCAPABILITY_REVOKED: Capability revokedORIGIN_MISMATCH: Origin mismatchBRANCH_MISMATCH: Branch mismatchEPOCH_MISMATCH: Epoch mismatchNONCE_VIOLATION: Nonce violationDOMAIN_SEPARATION_ERROR: Domain separation errornpm test
npm run test:integration
import { OctraSDK } from '@octra/sdk';
const sdk = await OctraSDK.init({
skipSignatureVerification: true, // For testing only!
});
Breaking Changes:
code, layer, retryableMigration 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:
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
Contributions are welcome! Please:
MIT License - see LICENSE file for details
For security issues, please email: security@octra.network
Do NOT open public issues for security vulnerabilities.
Built with ❤️ by the Octra Team
FAQs
Official TypeScript SDK for integrating dApps with OctWa Wallet Extension. Implements capability-based authorization with full HFHE support.
We found that @octwa/sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.