Contractless-Web3-Wallets/core/README.md

3.9 KiB

Contractless Browser Core

The core directory contains the deterministic cryptography and transaction codec layer for the Contractless Web3 wallet. Its Rust crate and generated WASM package retain the name contractless-browser-core.

The crate is intentionally independent from the Contractless node runtime. It does not connect to RPC servers, broadcast transactions, access PostgreSQL or Sled, run Tokio tasks, or read files from the operating system.

The browser wallet is responsible for:

  • obtaining wallet files through browser file APIs;
  • keeping decrypted private keys inside the extension;
  • presenting transaction details for user approval;
  • calling this package to hash, sign, verify, and encode transactions; and
  • sending signed transaction bytes to a configured Contractless PHP API.

The initial API exposes:

  • Skein-128, Skein-256, and Skein-512 hashing;
  • FN-DSA signing and verification;
  • public-key to short-address derivation; and
  • short-address byte encoding and decoding.
  • signed transfer creation and fixed 750-byte transfer decoding.
  • strict inspection and signing for every externally submitted transaction type;
  • signer-role checks against the wallet public key;
  • staged signing for swaps and loans; and
  • exact fixed-width wire encoding for completed transactions.
  • domain-separated website message signing and verification.
  • browser-native wallet generation and AES-256-GCM encrypted storage;
  • direct import from existing Contractless private-key images;
  • direct import from hexadecimal FN-DSA private keys;
  • export compatibility with existing Contractless wallet images; and
  • wallet-registration payload creation.

Browser transfer inputs use decimal strings for value and txfee. This prevents JavaScript's numeric precision limit from changing a signed u64 value.

Fixed transaction codecs will be added individually and tested against the native Contractless implementation before they are used by the wallet.

Wallet storage

New browser wallets encrypt their FN-DSA private key with AES-256-GCM. The key is derived from the wallet password with PBKDF2-SHA256 and a unique random salt. Only the encrypted wallet JSON is stored persistently by the extension.

Existing Contractless wallet files can be imported with their encryption key. Browser wallets can also be exported back to the existing wallet image format for use with the CLI or desktop wallet. The encrypted browser-wallet backup and its password are both required for recovery.

Transaction request flow

Websites submit unsigned transaction JSON to inspect_transaction_request. The core rejects unsupported types, missing fields, extra fields, invalid addresses, incorrect fixed-width values, and malformed numeric values. The returned review object is the canonical data the wallet must show to the user.

After approval, sign_transaction_request receives the wallet private and public keys. The public key determines the wallet address, and that address must match the signer role stored in the transaction.

For swaps and loans, signer two must also provide signer one's registered public key. The core verifies the first signature before adding the second. Only a complete transaction receives bytes_hex suitable for broadcasting.

Genesis and mining reward transactions are intentionally excluded from the signing registry because users and websites must never create them.

Website message proofs

sign_message_request signs a short-lived website proof without creating a transaction. The signed payload contains the requesting origin, wallet address, message, random nonce, issue time, and expiration time.

Message proofs use a Contractless-specific domain prefix. Their signatures cannot be reused as transaction signatures. Proofs are limited to 15 minutes, and production origins must use HTTPS.

verify_message_proof verifies the public key, derived wallet address, signature, expected origin, expected nonce, and current validity window.