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

shaheen

v1.1.1

Published

Android-first, polyfill-free Solana Mobile Wallet Adapter (MWA 2.0) native protocol engine using Rust

Readme


Why Shaheen?

Traditional Solana mobile integration on React Native requires heavy JavaScript polyfills (Buffer, react-native-quick-crypto, react-native-get-random-values), which slow down the Hermes runtime and complicate Metro configurations.

Shaheen moves the entire MWA 2.0 protocol into compiled native Rust:

  • ⚡ Native Performance — P-256 key exchange, HKDF-SHA256 derivation, and AES-128-GCM execute in native code off the JavaScript thread.
  • 🚀 No MWA Crypto Polyfills — Shaheen's MWA cryptography and transport run natively, so Shaheen itself does not require JavaScript crypto polyfills or Metro crypto shims.
  • 📱 Native Android Architecture — MWA transport and cryptography execute off the JavaScript thread in a Rust native core, with asynchronous Android execution.
  • 🔒 MWA 2.0 dApp API — Supports authorization, capability discovery, message signing, transaction signing/sending, and deauthorization.
  • 🧠 Intelligent Batching — Automatically chunks transactions to conform to wallet max_transactions_per_request constraints.
  • 🛡️ Typed Error Taxonomy — Clean exception classes (UserRejectedError, TimeoutError, etc.) replace untyped string errors.

Scope

What Shaheen Is

Shaheen is a native Android implementation of the dApp side of the Solana Mobile Wallet Adapter (MWA) 2.0 protocol for React Native and Expo.

It provides:

  • MWA wallet association
  • MWA 2.0 handshake and encrypted transport
  • Wallet authorization
  • Capability discovery
  • Message signing
  • Transaction signing
  • Transaction signing and sending
  • Deauthorization
  • Session management

What Shaheen Is Not

Shaheen is not:

  • A Solana RPC client
  • A Solana transaction-building library
  • A wallet
  • A replacement for @solana/web3.js
  • A replacement for the MWA protocol

Your application can continue using @solana/web3.js or another Solana library for transaction construction and RPC while using Shaheen for MWA wallet communication.


Compatibility

Shaheen is a dApp-side implementation of the Solana Mobile Wallet Adapter (MWA) 2.0 protocol.

It is designed to communicate with wallets that implement the MWA protocol. Wallet compatibility therefore depends on the wallet supporting MWA; Shaheen does not require a separate Shaheen-specific integration in the wallet.

Shaheen can be used alongside Solana transaction and RPC libraries such as @solana/web3.js.

@solana/web3.js
       │
       │ Build / serialize transaction
       ▼
   Uint8Array
       │
       ▼
     Shaheen
       │
       │ MWA 2.0
       ▼
MWA-compatible wallet

Shaheen is not intended to replace Solana RPC or transaction libraries. It provides the dApp-side wallet communication layer.


Architecture

Shaheen separates the React Native API from the MWA protocol engine.

React Native application
        │
        ▼
   Shaheen JS API
        │
        ▼
 Android native layer
        │
        │ JNI / native calls
        ▼
     Rust core
        │
        ├── Association
        ├── MWA 2.0 handshake
        ├── ECDH + HKDF
        ├── AES-128-GCM
        ├── Sequence validation
        ├── JSON-RPC
        └── WebSocket transport
        │
        ▼
 MWA-compatible wallet

The Rust core owns the MWA protocol, cryptographic operations, session state, sequencing, and transport. The Android layer provides the React Native and Android platform integration.

Shaheen follows the MWA 2.0 wire protocol. Its internal implementation language and React Native integration do not change the protocol spoken to wallets.

Data Handling

Shaheen accepts standard Solana transaction/message data and keeps the MWA wire serialization inside the native protocol engine.

MWA still uses its specified JSON-RPC and base64 payload representation on the wallet-facing wire. Shaheen's native implementation is designed to avoid unnecessary JavaScript-side cryptographic and protocol processing.

React Native Architecture

Shaheen 1.1 uses an Android native module with a Rust protocol core. MWA cryptography, session management, protocol framing, and transport execute natively rather than in JavaScript.

The React Native integration is intentionally kept thin. A future release may further reduce JavaScript/native serialization overhead through the React Native New Architecture and a more direct binary data path without changing the MWA 2.0 wire protocol or the public Shaheen API.


Installation

npm install shaheen @solana/web3.js
# or
yarn add shaheen @solana/web3.js
# or
pnpm add shaheen @solana/web3.js

Expo Setup

Add the plugin to your app.json:

{
  "expo": {
    "plugins": ["shaheen"]
  }
}

The config plugin automatically injects required Android intent queries (solana-wallet) into AndroidManifest.xml.

Bare React Native Setup

Add the intent query to android/app/src/main/AndroidManifest.xml:

<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="solana-wallet" />
    </intent>
</queries>

Quickstart

All operations take place inside a single, stateful wallet session via transact():

import { transact, UserRejectedError, TimeoutError } from 'shaheen';
import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js';

async function sendSol() {
  try {
    const result = await transact(async (wallet) => {
      // 1. Authorize session
      const auth = await wallet.authorize({
        chain: 'solana:mainnet',
        identity: {
          name: 'My Dapp',
          uri: 'https://mydapp.com',
          icon: 'favicon.ico',
        },
      });

      // 2. Build standard Solana transaction
      const tx = new Transaction().add(
        SystemProgram.transfer({
          fromPubkey: new PublicKey(auth.publicKey),
          toPubkey: new PublicKey('RecipientAddressHere1111111111111111111111'),
          lamports: 0.01 * LAMPORTS_PER_SOL,
        })
      );
      tx.feePayer = new PublicKey(auth.publicKey);
      tx.recentBlockhash = 'RecentBlockhashHere...';

      // 3. Sign & send via wallet
      const [signature] = await wallet.signAndSendTransactions([tx]);
      return { address: auth.publicKey, signature };
    });

    console.log('Transaction Confirmed:', result.signature);
  } catch (error) {
    if (error instanceof UserRejectedError) {
      console.warn('User rejected approval');
    } else if (error instanceof TimeoutError) {
      console.error('Wallet connection timed out');
    } else {
      console.error('Operation failed:', error);
    }
  }
}

API Overview

Inside transact(async (wallet) => { ... }), the wallet client provides:

| Method | Description | | :--- | :--- | | wallet.authorize(options) | Authenticates session with wallet; returns public key, auth token, and accounts. | | wallet.getCapabilities() | Queries wallet constraints (maxTransactionsPerRequest, supported features). | | wallet.signMessages(messages) | Signs arbitrary strings or Uint8Array messages (Sign-In with Solana). | | wallet.signAndSendTransactions(txs) | Signs and broadcasts an array of transactions with capability-aware chunking. | | wallet.deauthorize() | Revokes authorization token and clears session secrets. | | wallet.signTransactions(txs) | (Deprecated in MWA 2.0) Signs transactions offline without broadcasting. |

Message Signing (Sign-In with Solana)

await transact(async (wallet) => {
  await wallet.authorize();

  const [signatureBytes] = await wallet.signMessages([
    'Sign-In with Solana: ' + Date.now(),
  ]);

  console.log('Signature:', signatureBytes);
});

Capability Discovery & Smart Batching

await transact(async (wallet) => {
  // Query wallet limits
  const caps = await wallet.getCapabilities();

  // Shaheen automatically splits arrays larger than wallet limits into valid sub-batches
  const signatures = await wallet.signAndSendTransactions([tx1, tx2, tx3, tx4, tx5]);
});

Silent Re-Authorization

// Persist the token from first authorization
const auth = await wallet.authorize({ chain: 'solana:mainnet' });
await AsyncStorage.setItem('mwa_auth_token', auth.authToken);

// Re-authorize silently on future sessions without user prompt
const savedToken = await AsyncStorage.getItem('mwa_auth_token');
const silentAuth = await wallet.authorize({
  chain: 'solana:mainnet',
  authToken: savedToken ?? undefined,
});

Error Handling

Shaheen provides a structured exception taxonomy:

import {
  ShaheenError,
  UserRejectedError,
  TimeoutError,
  AuthorizationError,
  WalletUnavailableError,
  CapabilityError,
  ProtocolError,
  HandshakeError,
} from 'shaheen';

Cryptographic Benchmarks

Measured on a release build of shaheen_core across 1,000 iterations (cargo bench):

| Operation | Standard | Latency | | :--- | :--- | :--- | | Association Keypair Gen | NIST P-256 (secp256r1) | ~412 µs | | HELLO_REQ Signature | ECDSA-SHA256 (IEEE P1363) | ~889 µs | | HELLO_REQ Verification | ECDSA-SHA256 | ~801 µs | | Session Key Derivation | P-256 ECDH + HKDF-SHA256 | ~411 µs | | Payload Encryption (300B) | AES-128-GCM + 4B Seq AAD | ~1.3 µs | | Payload Decryption (300B) | AES-128-GCM + 4B Seq AAD | ~1.2 µs | | Native Cryptographic Pipeline | Key generation + ECDSA + ECDH + AES | ~1.73 ms CPU |

These measurements cover native cryptographic computation only. They do not represent end-to-end wallet transaction latency, which also includes React Native/native invocation, WebSocket transport, Android activity switching, wallet processing, user interaction, and Solana network/RPC latency.


Security Architecture

  • Key Separation — NIST P-256 Association Keypair $(Q_a, d_a)$ is isolated from the Ephemeral Handshake Keypair $(Q_d, d_d)$.
  • Spec Wire Framing — Strict 129-byte unencrypted HELLO_REQ wire format ($Q_d \parallel S_a$).
  • Monotonic AAD Validation — Every message enforces a strict, incremental 4-byte sequence counter as AES-GCM Additional Authenticated Data to protect against replay attacks.
  • Zeroization — Sensitive private-key and session-key structures use ZeroizeOnDrop to reduce the lifetime of cryptographic material in memory.
  • Unwind Isolation — Rust FFI entry points use catch_unwind to prevent Rust panics from unwinding across the FFI boundary.

License

MIT © Shaheen Contributors