solana_kit_mobile_wallet_adapter_protocol 0.5.3 copy "solana_kit_mobile_wallet_adapter_protocol: ^0.5.3" to clipboard
solana_kit_mobile_wallet_adapter_protocol: ^0.5.3 copied to clipboard

Pure Dart implementation of the Solana Mobile Wallet Adapter protocol v2.0. Provides cryptography, message framing, JSON-RPC types, and session management without Flutter dependencies.

solana_kit_mobile_wallet_adapter_protocol #

pub package docs website CI coverage

Pure Dart implementation of the Solana Mobile Wallet Adapter v2.0 protocol. It handles P-256 cryptography, session handshakes, encrypted message framing, JSON-RPC request/response encoding, association URI building/parsing, and protocol version negotiation.

The package has zero Flutter dependency and runs in server-side Dart, CLI tools, or any Dart environment.

Public-key import validates that uncompressed keys encode finite points on P-256. ECDH also checks the key domains and curve equation before multiplying by the private scalar. Malformed points, noncanonical coordinates, and mismatched curves throw ArgumentError.

createSiwsMessage rejects carriage returns and line feeds in scalar fields and resource entries with FormatException, preventing fields from injecting additional signed lines. Valid single-line messages remain unchanged.

What it covers #

  • P-256 ECDSA/ECDH cryptography via pointycastle (pure Dart, cross-platform)
  • AES-128-GCM encryption with sequence number AAD for replay attack prevention
  • HKDF-SHA256 key derivation with association public key as salt
  • HELLO_REQ / HELLO_RSP handshake for session establishment
  • JSON-RPC 2.0 message encryption/decryption
  • Association URI building and parsing (local + remote)
  • Wallet proxy with v1/legacy backwards compatibility
  • Sign In With Solana (SIWS) message builder following EIP-4361
  • JWS ES256 compact serialization for attestation
  • Central error codes integrated with solana_kit_errors

Installation #

Install the package directly:

dependencies:
  "solana_kit_mobile_wallet_adapter_protocol": ^0.5.3

If your app uses several Solana Kit packages together, you can also depend on the umbrella package instead:

dart pub add solana_kit

Inside this monorepo, Dart workspace resolution uses the local package automatically.

Documentation #

For architecture notes, getting-started guides, and cross-package examples, start with the workspace docs site and then drill down into the package README and API reference.

Usage #

Association keypair generation #

import 'package:solana_kit_mobile_wallet_adapter_protocol/solana_kit_mobile_wallet_adapter_protocol.dart';

void main() {
  // Generate keypairs for a new session.
  final associationKeypair = generateAssociationKeypair();
  final ecdhKeypair = generateEcdhKeypair();

  // Get the association token (base64url-encoded public key).
  final token = getAssociationToken(associationKeypair.publicKey);

  print(token);
  print(ecdhKeypair.publicKey);
}

Building association URIs #

Wallet-specific baseUri paths are preserved with or without a trailing slash. Parsing identifies the final association endpoint, so wallet path prefixes containing local or remote do not change the association type.

import 'dart:typed_data';

import 'package:solana_kit_mobile_wallet_adapter_protocol/solana_kit_mobile_wallet_adapter_protocol.dart';

void main() {
  final associationKeypair = generateAssociationKeypair();

  // Local association (same-device).
  final uri = buildLocalAssociationUri(
    associationKeypair.publicKey,
    55123,
  );
  // -> solana-wallet:/v1/associate/local?association=...&port=55123

  // Remote association (via reflector).
  final reflectorId = Uint8List.fromList([1, 2, 3]);
  final remoteUri = buildRemoteAssociationUri(
    associationKeypair.publicKey,
    'reflect.example.com',
    reflectorId,
  );

  print(uri);
  print(remoteUri);
}

HELLO handshake #

import 'dart:typed_data';

import 'package:solana_kit_mobile_wallet_adapter_protocol/solana_kit_mobile_wallet_adapter_protocol.dart';

void main() {
  final associationKeypair = generateAssociationKeypair();
  final ecdhKeypair = generateEcdhKeypair();

  // Create HELLO_REQ (129 bytes: 65B ECDH pubkey + 64B ECDSA signature).
  final helloReq = createHelloReq(ecdhKeypair, associationKeypair);

  // Parse HELLO_RSP from the wallet.
  final helloRspBytes = Uint8List(129);
  final result = parseHelloRsp(helloRspBytes, associationKeypair, ecdhKeypair);
  final sharedSecret = result.sharedSecret; // 16-byte AES key

  print(helloReq.length);
  print(sharedSecret);
}

Encrypted messaging #

import 'dart:typed_data';

import 'package:solana_kit_mobile_wallet_adapter_protocol/solana_kit_mobile_wallet_adapter_protocol.dart';

void main() {
  final sharedSecret = Uint8List(16);

  // Encrypt a JSON-RPC request.
  final encrypted = encryptJsonRpcRequest(
    1, // sequence number
    'authorize',
    {'chain': 'solana:mainnet'},
    sharedSecret,
  );

  // Decrypt a JSON-RPC response.
  final encryptedBytes = Uint8List(0);
  final response = decryptJsonRpcResponse(encryptedBytes, sharedSecret);

  print(encrypted);
  print(response);
}

Wallet proxy #

import 'package:solana_kit_mobile_wallet_adapter_protocol/solana_kit_mobile_wallet_adapter_protocol.dart';

Future<void> main() async {
  // Create a wallet proxy that handles v1/legacy compatibility.
  final sendRequest = (String method, Map<String, Object?> params) async {
    return <String, Object?>{};
  };
  final sessionProps = const SessionProperties(
    protocolVersion: ProtocolVersion.v1,
  );
  final wallet = createMobileWalletProxy(sendRequest, sessionProps);

  final authResult = await wallet.authorize({
    'identity': {'name': 'My dApp'},
    'chain': 'solana:mainnet',
  });

  print(authResult);
}

Protocol details #

Wire format #

Each encrypted message follows this binary format:

[4B sequence number (big-endian)] [12B random IV] [ciphertext + 16B GCM tag]

The 4-byte sequence number is also used as AAD (Additional Authenticated Data) for AES-GCM, preventing replay attacks.

Handshake flow #

  1. dApp generates association keypair (P-256 ECDSA) and ECDH keypair (P-256)
  2. dApp sends HELLO_REQ: [65B ECDH pubkey][64B ECDSA signature]
  3. Wallet sends HELLO_RSP: [65B wallet ECDH pubkey][optional encrypted session props]
  4. Both sides derive shared secret via ECDH + HKDF-SHA256 -> 16-byte AES key
  5. All subsequent messages use AES-128-GCM with incrementing sequence numbers

Protocol versions #

  • v1: Uses chain identifiers (solana:mainnet, solana:devnet, solana:testnet), feature arrays, and separate reauthorize method
  • legacy: Uses cluster names (mainnet-beta, devnet, testnet), boolean feature flags (supports_sign_and_send_transactions), and authorize with auth_token for reauthorization

Example #

Use example/main.dart as a runnable starting point for solana_kit_mobile_wallet_adapter_protocol.

  • Import path: package:solana_kit_mobile_wallet_adapter_protocol/solana_kit_mobile_wallet_adapter_protocol.dart
  • This section is centrally maintained with mdt to keep package guidance aligned.
  • After updating shared docs templates, run docs:update from the repo root.

Maintenance #

  • Validate docs in CI and locally with docs:check.
  • Keep examples focused on one workflow and reference package README sections for deeper API details.
0
likes
150
points
1.99k
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Pure Dart implementation of the Solana Mobile Wallet Adapter protocol v2.0. Provides cryptography, message framing, JSON-RPC types, and session management without Flutter dependencies.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

pointycastle, solana_kit_codecs_strings, solana_kit_errors

More

Packages that depend on solana_kit_mobile_wallet_adapter_protocol