crossmint_flutter 0.2.1
crossmint_flutter: ^0.2.1 copied to clipboard
Flutter SDK for Crossmint wallets, authentication, signers, embedded checkout, and verifiable credentials. Headless-first — you own the UI.
0.2.1 #
- Solana device signers are no longer rejected client-side. Support is provider-dependent (Swig/Crossmint support device signers, Squads does not) and validated server-side. When a provider rejects a device signer, the runtime transparently falls back to the recovery signer.
- A default device signer is still not eagerly attached to Solana wallet creation, since the backing provider is only known server-side. Explicitly requested device signers now flow through to the server.
- Once a wallet's provider is known not to support device signers, selecting a device signer is rejected before any local key is generated.
- Decoupled
permissionless_passkeys(andpermissionless), dropping the AndroidminSdkfloor from 30 to 24. The experimentalPermissionlessPasskeySignerFactoryis removed; the default passkey factory now yieldswalletUnsupportedPasskeySignerunless a host supplies its own. The supported callback-based passkey path (onCreatePasskey/onSignWithPasskey) is unaffected. - Bumped sub-package floors to
crossmint_core ^0.1.4andcrossmint_wallets ^0.1.3.
0.2.0 #
- Breaking: the minimum iOS deployment target is now 15. This SDK depends
on
crossmint_device_signer0.2.0, whose sharedCrossmintDeviceSignernative pod requires iOS 15. Because the dependency is direct, the floor applies to every consumer's iOS build at CocoaPods resolution time — not only apps that call the device signer at runtime. - Device signer: the hidden device-signer plugin adapter and software
key-storage now delegate to the shared native
CrossmintDeviceSignerpackages — the same native code the React Native SDK uses — for cross-SDK parity. No Dart API change. - Docs: dartdoc / API-reference style pass across the public surface (EVM payer override methods, checkout line-item factories, button properties, inlined enum values, lowercased dartdoc references) for the pub.dev landing page.
- Docs: corrected the hidden signer WebView dartdoc — it is hidden via a 1×1
Opacity(0.01)+IgnorePointerwrapper, not theOffstagewidget — and added a comment explaining why (a zero-area or unpainted WKWebView is reported as not visible on iOS, throttling JS timers and risking WebContent process termination). Mirrors crossmint-sdk React Native PR #1878.
0.1.4 #
- Fix:
addSignernow swaps the runtime wallet's_signerto the recovery signer before approving the pending registration, then restores the previous signer in afinally. Registering a signer is an admin-level op — the backend addresses the pending approval to the wallet's recovery signer, not to whichever signer is currently active. Before this change, callingaddSigner(device2)while signing withdevice1threwsignerApprovalSignerMissingbecause the pending approval'semail:...locator did not match the device signer. Matches the TS SDK (packages/wallets/src/wallets/wallet.ts). Callers that previously worked around this with an explicituseSigner(recovery)beforeaddSignerno longer need to.
0.1.3 #
- Docs: README refresh. Quickstart restructured into four numbered steps
(initialize client → sign user in → mount wallet host → load or create
wallet), with a new "OTP prompt handling" reference subsection covering
both the controller-driven and
onAuthRequiredcallback paths. Documents theCrossmintWalletdata-model vs runtime-wallet split and the four signer-bundled wallet factory helpers (createEvmWalletWithDeviceSigner/…WithNonCustodialSigner/…WithExternalWalletSigner/…WithPasskeySigner). Calls out thatCrossmintWalletControllerConfig.showOtpSignerPromptis inert plumbing today and points atcrossmintDefaultOtpPromptBuilderinstead. Flags theCrossmintEmailSignerConfig()recovery-signer assumption that the signed-in user has an email. - Docs: Embedded Checkout section expanded with a widget-parameter
reference table, a recipient-type guide (
CrossmintCheckoutEmailRecipient/…WalletRecipient/…PhysicalRecipient), a theming subsection coveringCrossmintCheckoutAppearance(variables / rules / fonts), andonOrderCreationFailedalongsideonDiagnostic. Corrects theonOrderUpdatedexample — the callback receivesMap<String, Object?>, so field access usesorder['orderId']rather thanorder.orderId. - Docs: New Platform Setup section covering the Android
AndroidManifest.xmlintent-filter and iOSInfo.plistCFBundleURLTypesentries required for OAuth deep links and theCrossmintAuthCallbackRouterto work. - No code changes. Root package version bumped to 0.1.3 so consumers see the updated README on pub.dev; sub-packages unchanged.
0.1.2 #
- Expanded dartdoc coverage across the public API:
CrossmintClient,CrossmintClientConfig,CrossmintWalletController,CrossmintWalletHost,CrossmintWalletProvider[Config], the EVM / Solana / Stellar runtime wallet classes, everyCrossmintWalletApprovalSignerimplementation (device, non-custodial email/phone, external, API-key, exportable, passkey), theCrossmintAuthClientinterface, and theCrossmintExceptionhierarchy. - Expanded dartdoc coverage across the embedded checkout surface:
CrossmintCheckoutConfig, the recipient classes (Email,Wallet,Physical, +PhysicalAddress), the payment classes (Payment,FiatPayment,CryptoPayment), transaction result variants, diagnostic severity, line-item subclasses, and theCrossmintCheckoutPayer/CrossmintEvmWalletCheckoutPayerbridge. - Added library-level dartdoc headers to every public barrel file under
lib/and the sub-packages underpackages/. - Declared supported platforms (iOS, Android) in
pubspec.yamlso pub.dev no longer reports "unknown platforms" on the package page. - Rewrote
example/README.mdto lead with a minimal copy-paste quickstart (provider + gate + send token + embedded checkout) with the full playground documentation retained below. - Expanded the main
README.mdembedded checkout section with fiat-only, physical-goods, andonDiagnosticsnippets.
0.1.1 #
-
Aligned delegated email/phone signer serialization at wallet creation with the EVM OpenAPI schema. The
signers: [CrossmintEmailSignerConfig(...)]/CrossmintPhoneSignerConfig(...)shapes now serialize to the full{type, email|phone}object instead of the bareemail:/phone:locator string, closing a parity gap withaddSignerand the RN SDK. Forward-compat only — no end-user behavior change in this release: the Crossmint backend does not currently accept email or phone as delegated signer types on EVM. Tracking the backend-side addition separately. See discussion on #21 / #24. -
Fixed device signer approvals on every platform. Three coordinated changes:
- Software fallback (
SoftwareDeviceSignerKeyStorage, used on iOS Simulator, Android emulator, Expo Go, and dev builds without native hardware storage) was UTF-8-encoding the approval message before signing, but the backend delivers a base64-encoded digest. The software signer now base64-decodes the message before signing, matching the RN reference and the native plugins. - Software fallback had no low-S canonicalisation — ERC-4337 / SWIG
verifiers reject high-S signatures to avoid malleability. The
signer now replaces
swithn - swhens > n/2, matching{lowS: true}in the RN signer. - Signature encoding is now decimal (base-10)
r/severywhere (software fallback + native Android Keystore + native iOS Secure Enclave). Software previously emitted hex viaBigInt.toRadixString(16); the native plugins emitted hex with a0xprefix. The wallets API parsesr/sas non-negative decimal BigInt strings and rejects hex with HTTP 400.
Verified end-to-end against staging via the playground's
signers.device.createAndSignMessage/createAndSendTransaction/reuseWithEmptyConfigscenarios. Fixes #23 and the follow-up #31. - Software fallback (
-
Added early diagnostic for non-custodial (email/phone) signers when no
CrossmintWalletHost/CrossmintWalletProvideris mounted in the widget tree.useSigner(CrossmintEmailSignerConfig(...))previously returned cleanly and the first failure surfaced deep inside bridge request polling (StateError: Hidden signer bridge is not connected). It now throwsCrossmintSignerException(code: nonCustodialBridgeHostNotMounted)atuseSignertime with an actionable message. The check is applied to bothwallet.useSigner(...)and theCrossmintWalletController.create{Evm,Solana,Stellar}WalletWithNonCustodialSignerfactory helpers. Fixes #22. -
Added
CrossmintWalletHostandHiddenSignerBridgeHosttopackage:crossmint_flutter/crossmint_flutter_controllers.dart. Both widgets arewidgets.dart-only and satisfy the headless-first import invariant, so apps using their own design system no longer need to pull in the Material UI barrel to host the hidden signer bridge. Thecrossmint_flutter_ui.dartre-exports continue to work unchanged. README Quickstart updated with the wrapping example and the non-custodial-signer host requirement. -
Added
CrossmintErrorCode.nonCustodialBridgeHostNotMountedtocrossmint_core. -
Added a public
HiddenSignerBridgeRuntimeController.hasEverBeenHostedgetter that flipstruethe first time aHiddenSignerBridgeHostattaches a port and staystrueon detach — the signal that backs the new missing-host diagnostic. -
Fixed
useSigner(CrossmintDeviceSignerConfig())against a wallet that already has a device signer registered. The runtime used to unconditionally register a second device signer, which the backend treats as adding a new delegated signer gated behind an admin/recovery-OTP approval. It now inspects the wallet's delegated signers and reuses the registered device signer when exactly one exists and its key is present locally, avoiding the duplicate-signer OTP round-trip. Falls through to fresh registration when the wallet has no device signer, when multiple device signers create ambiguity, or when the referenced key is not available in local storage (reinstall / wiped-storage case). Refreshes the wallet snapshot once when the local snapshot lacksconfig.delegatedSigners(trimmed-response case). Fixes #27. -
Fixed
useSigner(CrossmintDeviceSignerConfig(publicKeyX, publicKeyY))— previously silently dropped the caller's public-key material and registered a brand-new key.publicKeyX/publicKeyYand the device locator encode the same material (device:<base64(0x04 ‖ x ‖ y)>), so the canonical locator is now derived from the supplied public key, verified against the wallet's registered device signers, and activated. ThrowsCrossmintSignerExceptionon mismatch or when only one ofpublicKeyX/publicKeyYis provided. Refreshes the wallet snapshot once on any local miss (addSignerdoes not keepwallet.raw.config.delegatedSignersin sync, so a stale snapshot may list a different device signer whilegetWallet(...)already includes the requested one). Fixes #29.
0.1.0 #
- Fixed
CrossmintNonCustodialSignerdeduplicating concurrentensureAuthenticated()callers so a single in-flight auth attempt no longer surfaces twoonAuthRequiredprompts for the same auth event. - Fixed
CrossmintSignerBridgeClientcross-talk between concurrent calls that share a response event (e.g. tworequest:signin flight). Requests are now serialized per response event so unrelated event pairs (e.g. aget-statuswhile asignis pending) still run in parallel. Source-compatible source break:CrossmintSignerBridgeClientis no longerconst-constructible (no in-tree callers usedconst, but downstream code that did will need to drop theconstkeyword). - Fixed
CrossmintWalletProviderLifecycle.disposeDependencies()to keep disposing the auth router and client when the wallet controller's disposer throws. Failures are reported viaFlutterErrorinstead of skipping the remaining cleanup. - Added
CrossmintDeserializationExceptionand typed parser helpers (requireString,optionalString,requireInt,requireBool,requireMap,requireMapList) incrossmint_core.CrossmintUser.fromJsonis migrated as the first caller; remaining model fromJson sites will follow in a separate PR. - Added
CrossmintErrorCodeenum tocrossmint_core— typed, machine-readable error codes for programmaticswitch/caseexception handling. All exception subclasses now carry an optionalcodefield (defaults tounknown). Codes cover auth, wallet, signer, credential, order, and token domains. - Added
CrossmintPollingConfigandcrossmintPoll()utility tocrossmint_core— exponential backoff with jitter replaces the previous flat 1-second polling loops in signature and transaction confirmation flows. Default: 1 s initial, 2x growth, 8 s cap, 60 attempts, random jitter in [50 %, 100 %) range. - Added ADR-001 documenting the decision to keep hand-written
fromJson()/toJson()methods rather than adoptingfreezedorjson_serializablecodegen, with clear re-evaluation triggers. - Added
CrossmintChainenum tocrossmint_core— typed, environment-aware chain validation covering all 24 mainnet chains, 20 testnet chains, Solana, and Stellar. IncludesfromApiValue()/tryFromApiValue()for safe parsing andvalidateForEnvironment()for automatic mainnet→testnet conversion in non-production environments. - Added
CrossmintApiKeySigner— a backend-only signer matching the official TypeScript SDK's API key signer. All signing is handled server-side; callingsignMessage()orsignTransaction()locally throws a descriptive error. - Added
CrossmintPasskeySignerConfigmodel andcrossmintGuardAgainstPasskeySigners()guard. Passkey/WebAuthn signers are blocked in Flutter (matching the official React Native SDK), with a clear error message guiding users to alternative signer types. - Added
CrossmintApiKeySignerConfigandCrossmintPasskeySignerConfigto theCrossmintSignerConfigsealed hierarchy incrossmint_wallets. - Added
fromJson()/toJson()factory methods to all core model classes:CrossmintWallet,CrossmintSignerConfig(polymorphic dispatch by type),CrossmintWalletSigner,CrossmintTransactionRecord,CrossmintSignatureRecord,CrossmintWalletBalanceSnapshot,CrossmintNftRecord,CrossmintWalletNftPage,CrossmintUser,CrossmintOrderRecord,CrossmintTokenAvailabilityRecord, and others. - Replaced hand-rolled base58 encoder/decoder (~65 lines) with the published
bs58package. The_decodeBase58()and_encodeBase58()helpers incrossmint_non_custodial_signer.dartnow delegate tobase58.decode()andbase58.encode(). - Upgraded chain-type detection helpers (
crossmintIsSolanaChain(),crossmintIsStellarChain(),_isSolanaChain()) to prefer enum-based matching viaCrossmintChain.tryFromApiValue()with string fallback for backward compatibility. - Validated iOS real-device integration tests on physical iPhone via Wi-Fi debugging, closing the last pending validation item. Hidden signer bridge and device signer plugin (Secure Enclave) both passed.
- Documented the Xcode 26.4 / Flutter #184254 workaround (Wi-Fi debugging) for future iOS physical-device test runs.
- Fixed headless order parsing to handle the live
order.orderIdresponse shape returned byPOST /api/2022-06-09/orders. - Fixed
scripts/dart_defines_from_env.shso JSON-valued Dart defines work with direct command substitution in the documentedflutter run/test $(...)flow. - Added a direct staging probe for orders / Worldstore so client-key vs server-key boundaries are documented with live evidence.
- Added release-readiness docs for gate disposition, Android/iOS evidence, and the release-candidate checklist.
- Clarified that externally gated scopes remain non-blocking amber when the Flutter SDK contract is already proven correct.
- Added example-workspace package overrides so
flutter driveand other example-side validation paths resolve the local package family consistently. - Switched the package family to publish-ready hosted dependency manifests while
keeping local monorepo development on
pubspec_overrides.yaml. - Added consumer-facing installation guidance for
crossmint_flutterand cleaned up template metadata in the native device-signer plugin package.
0.0.1 #
- Initial internal Flutter port workspace release.
- Added the core Crossmint Flutter client surface for auth, wallets, credentials, orders, tokens, and users.
- Added the device signer plugin, hidden signer bridge, example app, and test harnesses.
- Known gaps at this release stage: iOS real-device automation and staging scopes gated by project/backend configuration.