Adds the full Polkadot/Substrate connector + verifier, both sides, so
@luxwallet/connect covers every Lux Bridge family (supportedChains: dot).
TS:
- types: Chain += 'polkadot'; SignatureScheme += sr25519 / ed25519-substrate /
ecdsa-substrate. caip122 label 'Polkadot'.
- src/polkadot/connect.ts — raw window.injectedWeb3 (polkadot.js / Talisman /
SubWallet), signRaw({type:'bytes'}); extension wraps <Bytes>…</Bytes>.
- src/polkadot/verify.ts — PURE, async (sr25519 needs cryptoWaitReady),
fails closed. @polkadot/util-crypto (Apache-2.0; sr25519 via @scure/sr25519
MIT) signatureVerify over the wrapped bytes + SS58 decode/checksum binding.
Separate ./polkadot/verify entrypoint keeps the other 5 chains' verify core
@noble-pure & synchronous.
- verify.ts: verifyProofAsync (all 6) alongside sync verifyProof (5).
- 20 vitest cases (sr25519/ed25519/ecdsa round-trip, tamper, wrong addr,
SS58 checksum, fail-closed); 91 TS tests green.
Go (go/walletconnect/polkadot.go):
- sr25519 via github.com/oasisprotocol/curve25519-voi (BSD-3-Clause) —
NOT the LGPL-3.0 ChainSafe/go-schnorrkel. ed25519 stdlib; ecdsa decred
secp256k1 recover; SS58 via mr-tron/base58 + x/crypto/blake2b.
- Cross-language KATs: Go verifies the exact signatures the TS
@polkadot/util-crypto side produced (all 3 schemes). Full Go suite green.
- Zero copyleft: go-licenses report shows every new dep BSD-3/MIT/ISC.
Licensing landmine resolved permissively (zero GPL/LGPL/AGPL).
4.8 KiB
@luxwallet/connect
Multi-chain wallet connect + Sign-In-With-X for EVM, Solana, Bitcoin, TON, XRP, Polkadot.
One vocabulary, one canonical login message (CAIP-122),
one verifier. MIT licensed — zero GPL. This is the clean wallet stack; the
Uniswap-derived GPL bones stay quarantined in luxfi/exchange.
Why
@luxfi/wallet (Uniswap "Universe" fork) is GPL-3.0 and EVM-only. This package
is a from-scratch, permissively-licensed connector that any Hanzo/Lux/Zoo/Pars
surface — hanzo.id login, the browser extension, web and mobile apps — can use
to authenticate a wallet on any supported chain.
Architecture
connect(chain) ─► Account ─► signLogin(challenge) ─► SignedProof ─► verifyProof()
(browser, per-chain connector) (server, one pure fn)
caip122.ts— render/parse the canonical login message.build ∘ parseround-trips.verify.ts—verifyProof(proof, expected): parse → enforce domain/nonce/time → dispatch to the per-chain crypto verifier. Pure, fails closed, never throws.<chain>/— per-chain connector (browser) + verifier (pure crypto).go/walletconnect— Go port ofverifyProof, imported by Hanzo IAM so the server verifies identically.
Chain support
| Chain | Connect lib (license) | Login proof | Connector | Verifier |
|---|---|---|---|---|
| EVM | viem (MIT) — EIP-6963 / window.ethereum |
EIP-191 personal_sign |
✅ evm/connect.ts |
✅ secp256k1 recover |
| Solana | injected provider (Phantom/Solflare/Backpack) | ed25519 signMessage |
✅ solana/connect.ts |
✅ ed25519 |
| Bitcoin | sats-connect (MIT) — Xverse/Leather/Unisat |
BIP-322 | ✅ bitcoin/connect.ts |
✅ legacy + BIP-322 |
| TON | @tonconnect/sdk (Apache-2.0) |
ton_proof |
✅ ton/connect.ts |
✅ ed25519 envelope |
| XRP | @crossmarkio/sdk (MIT) — Crossmark |
signInAndWait |
✅ xrp/connect.ts |
✅ secp256k1 + ed25519 |
| Polkadot | window.injectedWeb3 (polkadot.js / Talisman / SubWallet) |
signRaw({type:'bytes'}) |
✅ polkadot/connect.ts |
✅ sr25519 + ed25519 + ecdsa |
All connect libs are MIT/Apache/ISC — no GPL anywhere in the dependency tree.
Polkadot verify uses @polkadot/util-crypto (Apache-2.0, sr25519 via @scure/sr25519
MIT) in TS, and oasisprotocol/curve25519-voi (BSD-3-Clause) in Go — deliberately
NOT the LGPL-3.0 ChainSafe/go-schnorrkel. Polkadot's verifier is async
(sr25519 needs cryptoWaitReady()); use verifyProofAsync for all chains or
verifyPolkadot standalone. The five other chains' verify core stays
@noble-pure and synchronous.
GemWallet is intentionally not wired: its only client, @gemwallet/api, ships
under a custom dual license requiring GemWallet's permission for public/commercial
use — incompatible with the MIT/Apache/ISC-only rule. Crossmark covers both XRPL
key types, so the XRP path is complete without it.
Architecture: server verify never pulls a wallet lib
The wallet libraries are optional peer dependencies. The server-side
verifyProof path imports only @noble/* + bs58:
import { verifyProof } from '@luxwallet/connect/verify'; // zero wallet libs
import { buildSiwxMessage } from '@luxwallet/connect/caip122'; // zero deps
Connectors live behind separate entrypoints, so a server bundle stays clean:
import { loginWithWallet, getConnector } from '@luxwallet/connect/connectors';
import { EvmConnector } from '@luxwallet/connect/evm/connect';
Use
// Server: mint a challenge
import { newChallenge, verifyProof } from '@luxwallet/connect';
const challenge = newChallenge({ domain: 'hanzo.id', uri: 'https://hanzo.id/login' });
// → store challenge.nonce, send challenge to the client
// Server: verify what comes back
const res = verifyProof(proof, { domain: 'hanzo.id', nonce: challenge.nonce });
if (res.ok) { /* res.address is authenticated on res.chain */ }
// Client (browser): connect a wallet and sign the challenge in one call.
import { loginWithWallet } from '@luxwallet/connect/connectors';
const { account, proof } = await loginWithWallet({ chain: 'evm', challenge });
// → POST `proof` to the server, which calls verifyProof(proof, { domain, nonce }).
// Or drive a connector directly:
import { getConnector } from '@luxwallet/connect/connectors';
const c = getConnector('solana');
const acct = await c.connect(); // provider.connect()
const p = await c.signLogin(acct, challenge); // ed25519 signMessage → SignedProof
Develop
pnpm install
pnpm test # vitest — crypto verifiers run against generated keypairs
pnpm typecheck
pnpm build
License
MIT © Lux Industries Inc.