libwallet 0.3.13
libwallet: ^0.3.13 copied to clipboard
Multi-chain TSS cryptocurrency wallet client. Supports EVM, Bitcoin, Solana and Monacoin via direct FFI to the Go libwallet core.
0.3.13 #
-
Logs routed over the event channel (fixes 0.3.12's silent logging on iOS). 0.3.12 wired every internal diagnostic through
wltlog, but the underlyinglog.Printfwrites to the Go runtime'sos.Stderr— which Flutter+iOS swallows entirely, and Flutter+Android filters out offlutter logsby default. End result: testers saw no output even withlogLevel: "debug". Fixed by routing every wltlog emission through the apirouter broadcast channel (same pipe Web3 requests / balance changes already use). -
New
LogEvent+client.logsstream: subscribe once at startup and forward todeveloper.log/printso the logs show up in Flutter's log output on every platform:import 'dart:developer' as developer; client.logs.listen((e) { developer.log(e.message, name: 'libwallet.${e.level}'); }); await client.info.setWalletInfo( clientId: '...', logLevel: kDebugMode ? 'debug' : 'off', );LogEventis also emitted on the generalclient.eventsstream for hosts that want a single subscription. -
Sink safety: a panic inside the sink falls back to stderr with no rethrow, so a broken logging pipeline can never take down a send.
0.3.12 #
- Leveled logging (
wltlog) controlled bysetWalletInfo: newLogLevelfield onWalletInfo. Valid:"debug" | "info" | "warn" | "error" | "off"; empty resolves to libwallet's auto-default —"debug"on dev binaries (gitTag empty),"info"on release binaries. Typical pattern:logLevel: kDebugMode ? "debug" : "off". Every log call site routes throughwltlog.{Debugf,Infof,Warnf, Errorf}; lines are prefixed[debug] / [info] / [warn] / [error]so testers can grep by level regardless of the host's logger.getWalletInfoalso returnseffectiveLogLevelso the host can see what libwallet actually resolved""to. - Ed25519 self-heal diagnostics: the self-heal now logs a
specific skip reason at every gate (nil account, no wallet,
GetEnv(ctx)nil,WalletByIdfailed, wrong curve, no keys, decrypt failed, empty want, already-correct), visible atdebug. The actual repair (Pubkey/Address flip) logs atinfo. Combined with the always-onwantvsacct.Pubkeyvswallet.Pubkeydump, a tester flippinglogLevel: "debug"gets everything needed to pin down why a Solana send fails. FindAccountnow runscheck()on the address-lookup path: previously only the ID-lookup branch refreshed Curve / Address — tx.From is almost always an address, so account records with an empty Curve (rare but possible) would silently short-circuit the Ed25519 self-heal's curve gate. Fixed by callingacct.check(e)after the by-Address fetch.- Pre-broadcast Ed25519 verify:
Transaction:signAndSendon Solana now runsed25519.Verify(fee_payer, message, sig)locally before sending to the RPC. Catches pubkey/key-share mismatches with a specific error message ("TSS key shares may be inconsistent with stored pubkey") instead of the generic Solana-side rejection. - Extended pre-flight repair to every Solana sign path: 0.3.11
put the pre-flight only in
Transaction:signAndSend. The shared helperwltacct.EnsureEd25519PubkeyOnAccountis now called fromAccount:signMessage(solana mode),Account:signTransaction,Account:signAndSendTransaction, and Web3solana_sign_message/solana_sign_transaction/solana_sign_send_transaction. The helper also saves the repaired Account row synchronously so the dApp's nextwindow.solana.publicKeyread returns the corrected address. - Per-RPC timing logs (at
debug): everyNetwork.DoRPC/DoRPCNamedemitsrpc: chain=X method=Y OK in Nms (B bytes)orFAIL in Nms: err. Quiet atinfo; noisy but invaluable when reproducing a bug. - Per-key-decrypt timing (
wallet-signlogs, atdebug): entry line with wallet id/threshold/keys/msg_len; per-key "decrypted in N ms (type=Password|StoreKey|…)". Pubkey mismatch detected during sign logs atwarn.
0.3.11 #
- Solana ed25519 self-heal across every sign path: 0.3.10 only
repaired the legacy pubkey encoding inside
Transaction:signAndSend. A tester reported sends still failing on 0.3.10, which turned out to be a different entry point:Account:signAndSendTransactionand the Web3solana_sign_{message,transaction,send_transaction}approvers bypassed the repair. Extracted the fix intowltacct.EnsureEd25519PubkeyOnAccountand wired it into every Solana-capable sign path, includingAccount:signMessage. The helper also saves the repaired Account row synchronously (not just via the asyncwallet:pubkey_repairedhandler) so the nextFindAccount/window.solana.publicKeyread returns the corrected address in the same request lifecycle. - Visibility log: self-heal now emits
ed25519-repair: account <id> (wallet <id>) pubkey/address repaired: ...tolog.Printfwhen it fires. If affected users report that sends still fail after upgrading, grep logs fored25519-repair:— presence confirms the native binary upgrade landed and the repair ran; absence means the app is still running a pre-0.3.9liblibwallet.<ext>from the package cache. - Regression test:
TestEdDSAWalletCreatenow asserts the storedWallet.Pubkeybyte-matches the canonical compressed-Y Ed25519 form, and that stdlibed25519.Verify(storedPubkey, msg, sig)accepts the TSS signature. Either assert would have caught the original 0.3.9 encoding bug locally — same rejection Solana does on-chain.
0.3.10 #
- Solana ed25519 self-heal now actually runs (follow-up to 0.3.9):
the self-heal path in 0.3.9 had a wrong type assertion against the
signing context — it silently never triggered, so affected wallets
kept failing every send attempt. Fixed to use
wltintf.GetEnv(ctx). Additionally, added a pre-flight repair step in the Solana send path that decrypts one key share BEFORE building the transaction and patchesacct.Pubkeyin-memory, so the first send on an upgraded install succeeds instead of needing a failed-then-retry cycle. New exported helperwltwallet.EnsureEd25519Pubkeyis a no-op when the wallet is already correct.
0.3.9 #
- Solana ed25519 pubkey fix (breaking for existing Solana wallets):
ed25519 wallets created pre-0.3.9 stored the X coordinate of the
Edwards point (big-endian) as the "public key" instead of the
standard compressed encoding (Y little-endian with X's sign bit in
the MSB of byte 31). Consequences: the displayed Solana address was
wrong, balance queries hit a different address from the one the
TSS signs with, and every
sendTransactionfailed with "Transaction did not pass signature verification". Fixed at wallet creation viaToEd25519PubKey().Serialize(). Existing broken wallets self-heal on the first sign attempt (which fails once, then the repair propagates to the wallet + linked accounts and the retry succeeds). - On-chain tx history backfill (EVM):
client.transactions.list()now includes on-chain activity, not just txs this install built. Triggered in the background onAccount:setCurrent/Network:setCurrent/ env init. First triesmodchain_historyByAddress, falls back to Otterscan'sots_searchTransactionsAfter(erigon v3). Newclient.txHistoryUpdatesstream fires when new rows land. - Immediate balance refresh after sends: every
Transaction: signAndSend/Account:signAndSendTransaction/mpurse_sendRawTransaction/solana_sign_send_transactionnow nudges the background balance poller. Users see the new balance within ~1 s instead of up to 60 s.
0.3.8 #
- Background balance polling: new
client.balanceChangesstream yields aBalancesChangedEvent(full{network, account, assets}snapshot) every 60 s when the current account / network balances change. Lifecycle-aware — pauses underLifecycle:update('background')/paused, resumes with an immediate poll onforeground/resumed/active. - RPC timeouts (reliability fix): all
Network.DoRPC/DoRPCNamedcalls are now bounded by a 30 s default deadline. A misbehaving upstream (dead Ethereum public RPC, stale Solana endpoint, etc.) can no longer wedge a goroutine forever. The balance poller uses a tighter 15 s cap. Callers that need a specific deadline can use the existingDoRPCCtx/DoRPCNamedCtx. Fixes an iOS CI hang. - Network:testRPC extended: now accepts
type=evm/solana/bitcoinand probes the right health method per family. EVM is still the default;RpcTestResultgainedsolanaVersion/solanaCluster/bitcoinChain/bitcoinBlocksfields +isEvm/isSolana/isBitcoingetters. - Android 16 KB page alignment: CI now builds every Android
.so(both the AAR and the Dart FFI set) with-Wl,-z,max-page-size=16384and verifies it withreadelf. Required for Android 15+ devices with 16 KB page size (Pixel 8+).
0.3.7 #
- Wallet-identity plumbing: new
client.info.setWalletInfo(clientId:, name?, version?)registers the host wallet with libwallet. TheclientIdis sent as theSec-ClientIdHTTP header on everyCrypto/WalletSign:*call, which the WalletSign backend uses to pick branded SMS / email copy, apply per-app rate limits, and tag audit logs.name/versionare stored for future use (untrusted display strings, diagnostics). Called once at startup; backward- compatible (header not sent if not configured). - EIP-6963 UUID fix: webview injection docs corrected — generate a
fresh UUIDv4 per page load (spec requirement), do NOT persist
across launches.
rdnsis the stable identifier dApps key off, notuuid. - Drop Unix-socket transport fallback: FFI is the only supported
transport now. Removed
LibwalletClient.connect(socketPath)/.fromSocket(socket),JsonRpcConnection, request framing helper, and the socket-based testserver binary.Transportinterface stays (test mocks still work) but has one implementation.
0.3.6 #
- WalletConnect v2: full wallet-side implementation.
client.walletConnectcovers pair / sessions / approveSession / rejectSession / respond / respondError / emitEvent / disconnect. Two sugar streams (walletConnectProposals,walletConnectRequests) deliver typedWcSessionProposal/WcSessionRequestobjects. Sessions persist across restarts (SQL-backed); relay reconnects with backoff. Protocol pieces implemented: X25519 + HKDF + ChaCha20-Poly1305 envelopes, Ed25519 relay JWT auth, CAIP-10/-2 namespace handling,wc_sessionPropose/Settle/Request/Event/Delete. Seedoc/walletconnect_integration.md. - Transaction simulation + decoding: new
client.transactions.simulate. On EVM (erigon v3 backend), usesdebug_traceCallwith thecallTracerto walk the full call frame tree and return every ERC-20 Transfer + Approval and every value-carrying CALL at any depth asTransactionSimulation.effects. Second pass withprestateTracer(diff mode) returns per-address native-balance deltas asbalanceChanges. Top-level calldata decoded intodecodedMethod+decodedArgs(native_transfer/erc20_transfer/erc20_approve/unknown). Revert reasons decoded from standardError(string)ABI. Solana wrapssimulateTransaction(logs + unitsConsumed + err). Bitcoin parses viaoutscript.BtcTx(inputs + outputs + fee). - WebView injection: new
client.web3.injectionScript(...)generates a JS blob exposing libwallet aswindow.ethereum(EIP-1193 + EIP-6963),window.solana(Wallet Standard), andwindow.mpurse(Monacoin — github.com/tadajam/mpurse). Full wiring walkthrough indoc/webview_integration.md. - Bitcoin-family message signing (via mpurse):
mpurse_signMessagesigns with the TSS key over the standard "\x18Bitcoin Signed Message:\n" / "\x19Monacoin Signed Message:\n" / etc. prefix, returning the 65-byte compact signature (base64, Bitcoin Coresignmessageformat).mpurse_signRawTransactionparses the hex, matches inputs to the user's xpub viamodchain_lookupTxoBIP32, signs each input, and returns the signed hex.mpurse_sendRawTransactionis a direct passthrough tosendrawtransaction.mpurse_sendAssetstill errors (Counterparty server interaction is out of scope). - Monacoin network support:
bitcoinAddressrecognizesmonacoinchain id and emits the bech32mona1...address viaoutscript.Out.Address("monacoin"). - Typed pending-request flow:
PendingRequestis now sealed with one subtype per Web3 request kind (ConnectRequest, PersonalSignRequest, SignTypedDataRequest, SolanaSign* / Mpurse* / …, UnknownPendingRequest). Therequestevent now carries the full request object so consumers can render the prompt on first paint without a follow-upRequest/<id>fetch. Newclient.pendingRequestsstream yields fully-parsed requests ready for pattern matching. - Example package layout: new
example/libwallet_example.dartCLI sample covering init / wallet create with live progress / account / balance / pendingRequests subscription. Satisfies pub.dev's example requirement. - pubspec: description trimmed to 129 chars (was 212) to satisfy pub.dev's metadata scan.
0.3.5 #
- Direct account signing: new
Account.signMessage,signTransaction,signAndSendTransactionendpoints let wallet-host apps sign directly without routing through the Web3 pending-request/approve flow. Removes ~80 lines of async listener code from the typical Dart integration. - View accounts (read-only):
accounts.createView(type:, address:, xpub:)creates accounts with no backing wallet — suitable for watching a counterparty address or an HD tree (xpub, bitcoin-family). Balance and NFT queries work; signing is rejected. NewAccount.isViewOnlygetter. - Progress redesign: progress events are now a single 0..1
fractioninstead of{count, running}. ECDSA wallet creation now emits fine- grained ticks during Paillier / NTilde safe-prime generation (one per prime found out of 4, per key) — previously the UI was blind for 20+ seconds per key share. Requires tss-lib v2.2.4+. - Typed-API cleanup: removed
dynamicreturns and rawMap<String, dynamic>param inputs across the API surface. New typed models:SignedMessage,RemoteKeySession,RemoteKeyValidation,NftListing,WalletBackupEntry,RpcTestResult,UnsignedTransaction. Methods liketransactions.signAndSend(UnsignedTransaction),wallets.backup(),remoteKeys.validate()now return proper model instances. Raw param maps oncontacts.update,networks.update,tokens.updatereplaced with named parameters. - Validation: reject wallet
Curvevalues outside{secp256k1, ed25519}; reject account type/curve mismatches (e.g.solanaon secp256k1,ethereumon ed25519). Bitcoin accounts now derive on BIP-44 coin_type 0 (m/44/0/0/i) instead of Ethereum's coin_type 60.
0.3.4 #
- Email 2FA:
RemoteKey:new(andremoteKeys.create) now accept an email address in addition to phone numbers. Pass eithernumberoremail— the EllipX backend routes SMS vs email verification based on whether the value contains@.
0.3.3 #
- Bitcoin balance fix:
modchain_assetsreturnsbalanceas a decimal-formatted number ("0.00000000"), not int64. Decode viaoutscript.BtcAmountwhich handles both forms. Previously failed with:json: cannot unmarshal number 0.00000000 into Go struct field. - Solana NFT fix:
getAssetsByOwner(Helius DAS API) requires named JSON-RPC params, not positional. NewNetwork.DoRPCNamed()helper. Previously failed with:invalid type: map, expected a string. - Bitcoin UTXO decode:
modchain_lookupTxoBIP32response uses the sameBtcAmountserialization foramtandbalancefields. Type switched from int64 to outscript.BtcAmount across wlttx/bitcoin.go. - EVM NFT lookup hardening: type assertions on the
modchain_assetsresponse in wltnet/nft.go could panic if any field was missing or the wrong type. Replaced with comma-ok form. - iOS Dart Tests CI timeout bumped 45 → 60 minutes (Xcode build slow).
0.3.2 #
- iOS simulator support: build hook now detects
iphoneosvsiphonesimulatorSDK and downloads the correct binary. Previously the simulator would try to link the device-only binary and fail. - Release now includes
liblibwallet-iossimulator-arm64.a(Apple Silicon) andliblibwallet-iossimulator-x64.a(Intel Mac simulators) alongside the existingliblibwallet-ios-arm64.adevice binary.
0.3.1 #
- Bitcoin HD address support:
bitcoin-type accounts now derive multi-address HD trees under their account xpub. Balance queries callmodchain_assets(xpub)which scans0..lastI+20child keys (BIP-44 style gap limit) server-side. - New
AccountApi.xpub(id): returns the BIP-32 extended public key. - New
AccountApi.nextAddress(id): returns the next clean receive (or change) address based on on-chain scan. - New
AccountApi.allAddresses(id): lists all HD addresses across receive and change chains with activity markers. Account.Addressnow points tom/0/0(first receive address) instead ofm/0for Bitcoin-family accounts. BTC/LTC/DOGE/BCH supported.
0.3.0 #
- EIP-1559 transactions: Auto-selected when the chain supports it. New
maxFeePerGasandmaxPriorityFeePerGasfields onTransaction. - ERC-20 transfers: New
erc20_transfertransaction type. Pass a token XUID inAsset, recipient inTo, and amount — libwallet encodes thetransfer(address,uint256)call automatically. - ENS / SNS name resolution: New
client.names.resolve('vitalik.eth')API. Auto-detects.eth(Ethereum) and.sol(Solana) suffixes. - Solana devnet: Routes to the correct Helius devnet RPC endpoint
when using a Solana network with
chainId: "devnet". - Local dev:
hook/build.dartnow prefers a localtestserver/liblibwallet.<ext>over downloading from GitHub Releases. - Fix: macOS dylibs built with
-headerpad_max_install_namesso Dart can bundle them without relinking.
0.2.0 #
- Auto-download native binaries from GitHub Releases at build time
- CI testing on macOS, Android emulator, and iOS simulator
- 43 integration tests covering all API endpoints
- Full dartdoc on all model fields (~130 fields)
- Comprehensive README with usage examples
0.1.0 #
- Initial release
- FFI transport with
NativeCallable.listenerfor Go→Dart callbacks - 17 typed API classes covering all libwallet endpoints
- 15 model classes with full dartdoc
- Socket transport as legacy fallback
- Native asset hook for pub.dev binary distribution