Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 0.1.1

- Support app_links 7.2.1; require Flutter 3.44 and Dart 3.12.
- Document wallet approval, transport, account adapters and request lifecycle APIs.
- Retain the CORE License, including its non-OSI status.

## 0.1.0

Initial Connect v1 implementation, shared conformance vectors, security tests, examples and release automation.
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Flutter wallet library for Connect v1. Handles full `connect://` links and QR te

```yaml
dependencies:
flutter_connect: ^0.1.0
flutter_connect: ^0.1.1
```

```dart
Expand Down Expand Up @@ -76,3 +76,5 @@ node scripts/flutter-interop.mjs
Shared vectors assert identical Dart/TypeScript messages. Dart Ed25519 signatures and an OpenSSL Ed448 host bridge also complete real Better Auth desktop sessions. The OpenSSL fixture requires OpenSSL 3 on the test host; it is not a mobile signing implementation. The standalone suite skips live-server tests unless the integration runner supplies its test endpoint.

See [release setup](doc/RELEASE.md). Licensed under the [CORE License](LICENSE).

This package is distributed under the [CORE License](LICENSE). It is not an OSI-approved license.
6 changes: 3 additions & 3 deletions doc/CHAINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Signing method availability depends on the host wallet. These are protocol adapt
## TypeScript wallet

```ts
import { chains, walletAccount } from 'connect.js';
import { chains, walletAccount } from 'connect-protocol';

const account = walletAccount(chains.solana, address, async bytes => {
const result = await wallet.signMessage(bytes);
Expand Down Expand Up @@ -76,7 +76,7 @@ All profiles prove possession of the key associated with the selected address. T

Cardano enforces protected EdDSA (`-8` inside legacy CIP-8 COSE, Ed25519 curve 6 and OKP key type 1), the exact protected address, the payload and a matching Blake2b-224 key credential. The Connect algorithm remains the fully specified Ed25519 identifier `-19`. Attached unhashed and Blake2b-224-hashed payloads are supported. Protected headers must be exactly algorithm and address; unprotected headers exactly `hashed`; COSE_Key exactly kty, alg, crv and x. Unknown/critical extensions, duplicate map keys, detached payloads, pointers, scripts and Byron addresses are rejected.

Monero verification lazily loads monero-project WASM through monero-ts, operates offline, validates the address checksum/network, and accepts only modern spend-key SigV2 proofs. Each verification closes its temporary in-memory wallet; it does not persist a wallet or contact a daemon. This is heavier than the other verifiers and requires WebAssembly. connect.js ships browser WASM chunks; better-connect owns the Node WASM loader and bundles its patched Monero dependency. The Bitcoin legacy signing library is used only in better-connect tests as an independent signing implementation; production recovery uses noble. Remaining low-severity elliptic audit notices are limited to that development dependency.
Monero verification lazily loads monero-project WASM through monero-ts, operates offline, validates the address checksum/network, and accepts only modern spend-key SigV2 proofs. Each verification closes its temporary in-memory wallet; it does not persist a wallet or contact a daemon. This is heavier than the other verifiers and requires WebAssembly. connect-protocol ships browser WASM chunks; better-connect owns the Node WASM loader and bundles its patched Monero dependency. The Bitcoin legacy signing library is used only in better-connect tests as an independent signing implementation; production recovery uses noble. Remaining low-severity elliptic audit notices are limited to that development dependency.

## Standards and references

Expand All @@ -88,4 +88,4 @@ Monero verification lazily loads monero-project WASM through monero-ts, operates
- [Litecoin signed messages](https://github.com/litecoin-project/litecoin/blob/master/src/util/message.cpp), [Zcash message magic](https://github.com/zcash/zcash/blob/master/src/main.cpp), [Zcash address versions and genesis](https://github.com/zcash/zcash/blob/master/src/chainparams.cpp).
- [CAIP namespaces](https://namespaces.chainagnostic.org/), [Base chain ID](https://docs.base.org/base-chain/api-reference/ethereum-json-rpc-api/eth_chainId), [Polygon chain ID](https://docs.polygon.technology/wallets/wallet-operations), [BNB configuration](https://docs.bnbchain.org/bnb-smart-chain/developers/wallet-configuration/).

The main `connect.js` import provides browser-only challenge creation and verification. `connect.js/verification` exposes signature profiles, and `connect.js/wallet` exposes wallet discovery and adapters. better-connect owns its backend engine, HTTP endpoints and session storage. connect.js has no server or dapp entry point.
The main `connect-protocol` import provides browser-only challenge creation and verification. `connect-protocol/verification` exposes signature profiles, and `connect-protocol/wallet` exposes wallet discovery and adapters. better-connect owns its backend engine, HTTP endpoints and session storage. connect-protocol has no server or dapp entry point.
2 changes: 1 addition & 1 deletion doc/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Implementation plan

1. Define Connect v1, strict schemas, canonical messages and shared vectors in connect.js.
1. Define Connect v1, strict schemas, canonical messages and shared vectors in connect-protocol.
2. Build profile verification and atomic request transitions, then Better Auth endpoints and normal session cookies.
3. Port wallet behavior to Dart, including lifecycle, transport and explicit approval.
4. Exercise cryptographic substitution attacks, concurrency, cross-language bytes and real Better Auth sessions.
Expand Down
13 changes: 10 additions & 3 deletions doc/VALIDATION.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# Implementation validation — 2026-09-07

Implemented locally in flutter_connect, connect.js and better-connect. No commits, pushes, tags or registry publications were made in the target repositories.
## 0.1.1 validation

Local pana 0.23.18 reports 150/160 points. Documentation scores 20/20 with 64 of 161 public API elements documented (39.8%); dependency support scores 40/40, including latest-version compatibility and lower-bound analysis. The remaining 10 points require an OSI-approved license; CORE License is intentionally retained unchanged.

The package now requires Flutter 3.44 and Dart 3.12 to support app_links 7.2.1. Static analysis, Flutter tests, and Android/iOS simulator builds pass. Registry scores will update only after this version is published and analyzed by pub.dev.


Implemented locally in flutter_connect, connect-protocol and better-connect. No commits, pushes, tags or registry publications were made in the target repositories.

## Results

| Check | Result |
| --- | --- |
| connect.js browser API/unit/conformance/lifecycle suite | 39 passed |
| connect-protocol browser API/unit/conformance/lifecycle suite | 39 passed |
| Chromium browser and installed-package verification | All 17 proof fixtures, fresh Core flow, lifecycle checks and static example passed |
| better-connect cryptographic/security/SQLite/client suite | 54 passed |
| Flutter standalone suite | 27 passed; the 17 live-server cases run separately below |
Expand All @@ -30,7 +37,7 @@ Local toolchain: Node 24.2.0, Flutter 3.47.2 / Dart 3.13.2, OpenSSL 3.6.4, Bette

## Delivered architecture and support

connect.js owns the browser-only API, strict v1 schemas, canonicalization, wallet adapters and local signature verification. It has no server, HTTP dapp client or request store. better-connect owns the backend request engine, Node Monero loading, persistent adapter storage, HTTP endpoints and Better Auth session cookies. Flutter ports the wallet protocol to Dart and adds app_links lifecycle integration. Shared vectors verify canonical bytes across all three packages.
connect-protocol owns the browser-only API, strict v1 schemas, canonicalization, wallet adapters and local signature verification. It has no server, HTTP dapp client or request store. better-connect owns the backend request engine, Node Monero loading, persistent adapter storage, HTTP endpoints and Better Auth session cookies. Flutter ports the wallet protocol to Dart and adds app_links lifecycle integration. Shared vectors verify canonical bytes across all three packages.

Named presets and built-in verification cover Core Blockchain, Ethereum, Polygon, Base, Bitcoin, Solana, BNB Smart Chain, TRON, Monero, Stellar, Litecoin, XRP, Zcash and Cardano, plus alternate Bitcoin legacy and XRP Ed25519 methods. Raw Ed25519 remains supported. [CHAINS.md](CHAINS.md) specifies address limits and encoding rules. Tests cover every chain through real signature verification, unrelated-key substitution, message-field changes, network/algorithm mismatches and one-time redemption. Additional checks use the official Core and Stellar vectors, independent Emurgo CIP-8 signing, Cardano protected-header and credential tampering, and rejection of Monero view-key authentication.

Expand Down
4 changes: 2 additions & 2 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: connect_wallet_example
description: Connect wallet reference application using an ephemeral Ed25519 test account.
publish_to: none
version: 0.1.0+1
version: 0.1.1+2
environment:
sdk: '>=3.9.0 <4.0.0'
sdk: '>=3.12.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
Expand Down
5 changes: 5 additions & 0 deletions lib/flutter_connect.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/// Wallet-side Connect authentication for dapps and optional Better Auth portals.
///
/// Resolve a full connect:// handoff with [ConnectClient], show its origin and
/// accounts, then call [ConnectRequest.approve] only after user confirmation.
/// The portal must verify wallet ownership before establishing a session.
library;

export 'src/protocol.dart';
Expand Down
20 changes: 17 additions & 3 deletions lib/src/chains.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class ConnectChain {
signatureEncoding;
final String? publicKeyEncoding;
final int? alg;

/// Defines a chain preset without implementing or invoking a signer.
const ConnectChain({
required this.name,
required this.namespace,
Expand All @@ -23,6 +25,8 @@ class ConnectChain {
required this.signatureEncoding,
this.publicKeyEncoding,
});

/// Creates an Ethereum-compatible chain using EIP-191 personal_sign proofs.
factory ConnectChain.evm(String name, int chainId) {
if (chainId <= 0 || chainId > 999999999999999) fail('invalidChain');
return ConnectChain(
Expand All @@ -35,8 +39,12 @@ class ConnectChain {
signatureEncoding: 'hex0x',
);
}

/// Policy entry a portal can use to accept accounts from this chain.
SigningRequirement get requirement =>
SigningRequirement(namespace, reference, profile, alg);

/// Binds an address claim to this chain; the portal must verify ownership.
SigningSelection account(String address) => SigningSelection(
account: WalletIdentity(
namespace: namespace,
Expand All @@ -48,6 +56,7 @@ class ConnectChain {
);
}

/// Built-in chain presets defining identities, signing methods and proof encodings.
abstract final class ConnectChains {
static const core = ConnectChain(
name: 'Core Blockchain',
Expand Down Expand Up @@ -217,6 +226,7 @@ abstract final class ConnectChains {
];
}

/// Returns immutable, deduplicated requirements for the selected chains.
List<SigningRequirement> requirementsFor(Iterable<ConnectChain> chains) {
final result = <String, SigningRequirement>{};
for (final chain in chains) {
Expand All @@ -228,15 +238,19 @@ List<SigningRequirement> requirementsFor(Iterable<ConnectChain> chains) {

/// Connect adapter around an existing wallet's message-signing operation.
class ChainWalletAccount implements WalletAccount {
/// Chain and address offered to compatible Connect requests.
@override
final SigningSelection selection;
final Future<WalletSignature> Function(Uint8List) _sign;

/// Adapts a host signer; the callback must preserve the canonical bytes.
ChainWalletAccount({
required ConnectChain chain,
required String address,
required Future<WalletSignature> Function(Uint8List) sign,
}) : selection = chain.account(address),
_sign = sign;
required this._sign,
}) : selection = chain.account(address);

/// Delegates canonical bytes to the host wallet without exporting its key.
@override
Future<WalletSignature> sign(Uint8List canonicalPayload) =>
_sign(canonicalPayload);
Expand Down
7 changes: 7 additions & 0 deletions lib/src/links.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ import 'wallet.dart';
/// Create early after WidgetsFlutterBinding.ensureInitialized().
/// Host applications own navigation and display errors through [onError].
class ConnectLinks {
/// Client that receives raw links for validation and user approval.
final ConnectClient client;

/// Receives link delivery or request validation errors for safe UI handling.
final void Function(Object error) onError;
final AppLinks _links;
StreamSubscription<String>? _subscription;
final Set<String> _delivered = {};

/// Creates a lifecycle bridge; inject AppLinks when testing OS delivery.
ConnectLinks({required this.client, required this.onError, AppLinks? links})
: _links = links ?? AppLinks();
Future<void> _handle(String uri) async {
Expand All @@ -21,6 +26,7 @@ class ConnectLinks {
}
}

/// Subscribes to warm links and handles the initial cold-start link once.
Future<void> start() async {
if (_subscription != null) return;
// String APIs preserve raw syntax; Uri.toString could normalize hostile input.
Expand All @@ -32,6 +38,7 @@ class ConnectLinks {
if (initial != null) await _handle(initial);
}

/// Stops OS link delivery without disposing the underlying Connect client.
Future<void> dispose() async {
await _subscription?.cancel();
_subscription = null;
Expand Down
Loading
Loading