crossmint_flutter 0.2.2 copy "crossmint_flutter: ^0.2.2" to clipboard
crossmint_flutter: ^0.2.2 copied to clipboard

Flutter SDK for Crossmint wallets, authentication, signers, embedded checkout, and verifiable credentials. Headless-first — you own the UI.

0.2.2 #

  • Upgraded app_links to ^7.0.0 and flutter_secure_storage to ^10.0.0.
  • These bumps raise upstream platform floors: flutter_secure_storage 10 requires Android minSdk 23, iOS 12, and Flutter 3.19.0; app_links 7 requires iOS 13 and Flutter 3.38.1. The SDK already targets iOS 15. The effective Flutter floor is 3.41.6 (the first Flutter shipping Dart 3.11.4, which the sdk: ^3.11.4 constraint requires); the environment block now declares this explicitly.
  • flutter_secure_storage 10 replaces the deprecated Jetpack Crypto backend on Android with new default ciphers and migrates existing entries automatically; it also defaults resetOnError to true. Hosts that pin custom AndroidOptions should review the package's v10 migration notes before upgrading.

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 (and permissionless), dropping the Android minSdk floor from 30 to 24. The experimental PermissionlessPasskeySignerFactory is removed; the default passkey factory now yields walletUnsupportedPasskeySigner unless a host supplies its own. The supported callback-based passkey path (onCreatePasskey / onSignWithPasskey) is unaffected.
  • Bumped sub-package floors to crossmint_core ^0.1.4 and crossmint_wallets ^0.1.3.

0.2.0 #

  • Breaking: the minimum iOS deployment target is now 15. This SDK depends on crossmint_device_signer 0.2.0, whose shared CrossmintDeviceSigner native 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 CrossmintDeviceSigner packages — 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) + IgnorePointer wrapper, not the Offstage widget — 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: addSigner now swaps the runtime wallet's _signer to the recovery signer before approving the pending registration, then restores the previous signer in a finally. 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, calling addSigner(device2) while signing with device1 threw signerApprovalSignerMissing because the pending approval's email:... 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 explicit useSigner(recovery) before addSigner no 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 onAuthRequired callback paths. Documents the CrossmintWallet data-model vs runtime-wallet split and the four signer-bundled wallet factory helpers (createEvmWalletWithDeviceSigner / …WithNonCustodialSigner / …WithExternalWalletSigner / …WithPasskeySigner). Calls out that CrossmintWalletControllerConfig.showOtpSignerPrompt is inert plumbing today and points at crossmintDefaultOtpPromptBuilder instead. Flags the CrossmintEmailSignerConfig() 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 covering CrossmintCheckoutAppearance (variables / rules / fonts), and onOrderCreationFailed alongside onDiagnostic. Corrects the onOrderUpdated example — the callback receives Map<String, Object?>, so field access uses order['orderId'] rather than order.orderId.
  • Docs: New Platform Setup section covering the Android AndroidManifest.xml intent-filter and iOS Info.plist CFBundleURLTypes entries required for OAuth deep links and the CrossmintAuthCallbackRouter to 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, every CrossmintWalletApprovalSigner implementation (device, non-custodial email/phone, external, API-key, exportable, passkey), the CrossmintAuthClient interface, and the CrossmintException hierarchy.
  • 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 the CrossmintCheckoutPayer / CrossmintEvmWalletCheckoutPayer bridge.
  • Added library-level dartdoc headers to every public barrel file under lib/ and the sub-packages under packages/.
  • Declared supported platforms (iOS, Android) in pubspec.yaml so pub.dev no longer reports "unknown platforms" on the package page.
  • Rewrote example/README.md to lead with a minimal copy-paste quickstart (provider + gate + send token + embedded checkout) with the full playground documentation retained below.
  • Expanded the main README.md embedded checkout section with fiat-only, physical-goods, and onDiagnostic snippets.

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 bare email: / phone: locator string, closing a parity gap with addSigner and 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:

    1. 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.
    2. Software fallback had no low-S canonicalisation — ERC-4337 / SWIG verifiers reject high-S signatures to avoid malleability. The signer now replaces s with n - s when s > n/2, matching {lowS: true} in the RN signer.
    3. Signature encoding is now decimal (base-10) r/s everywhere (software fallback + native Android Keystore + native iOS Secure Enclave). Software previously emitted hex via BigInt.toRadixString(16); the native plugins emitted hex with a 0x prefix. The wallets API parses r/s as 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 / reuseWithEmptyConfig scenarios. Fixes #23 and the follow-up #31.

  • Added early diagnostic for non-custodial (email/phone) signers when no CrossmintWalletHost / CrossmintWalletProvider is 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 throws CrossmintSignerException(code: nonCustodialBridgeHostNotMounted) at useSigner time with an actionable message. The check is applied to both wallet.useSigner(...) and the CrossmintWalletController.create{Evm,Solana,Stellar}WalletWithNonCustodialSigner factory helpers. Fixes #22.

  • Added CrossmintWalletHost and HiddenSignerBridgeHost to package:crossmint_flutter/crossmint_flutter_controllers.dart. Both widgets are widgets.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. The crossmint_flutter_ui.dart re-exports continue to work unchanged. README Quickstart updated with the wrapping example and the non-custodial-signer host requirement.

  • Added CrossmintErrorCode.nonCustodialBridgeHostNotMounted to crossmint_core.

  • Added a public HiddenSignerBridgeRuntimeController.hasEverBeenHosted getter that flips true the first time a HiddenSignerBridgeHost attaches a port and stays true on 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 lacks config.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/publicKeyY and 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. Throws CrossmintSignerException on mismatch or when only one of publicKeyX/publicKeyY is provided. Refreshes the wallet snapshot once on any local miss (addSigner does not keep wallet.raw.config.delegatedSigners in sync, so a stale snapshot may list a different device signer while getWallet(...) already includes the requested one). Fixes #29.

0.1.0 #

  • Fixed CrossmintNonCustodialSigner deduplicating concurrent ensureAuthenticated() callers so a single in-flight auth attempt no longer surfaces two onAuthRequired prompts for the same auth event.
  • Fixed CrossmintSignerBridgeClient cross-talk between concurrent calls that share a response event (e.g. two request:sign in flight). Requests are now serialized per response event so unrelated event pairs (e.g. a get-status while a sign is pending) still run in parallel. Source-compatible source break: CrossmintSignerBridgeClient is no longer const-constructible (no in-tree callers used const, but downstream code that did will need to drop the const keyword).
  • Fixed CrossmintWalletProviderLifecycle.disposeDependencies() to keep disposing the auth router and client when the wallet controller's disposer throws. Failures are reported via FlutterError instead of skipping the remaining cleanup.
  • Added CrossmintDeserializationException and typed parser helpers (requireString, optionalString, requireInt, requireBool, requireMap, requireMapList) in crossmint_core. CrossmintUser.fromJson is migrated as the first caller; remaining model fromJson sites will follow in a separate PR.
  • Added CrossmintErrorCode enum to crossmint_core — typed, machine-readable error codes for programmatic switch/case exception handling. All exception subclasses now carry an optional code field (defaults to unknown). Codes cover auth, wallet, signer, credential, order, and token domains.
  • Added CrossmintPollingConfig and crossmintPoll() utility to crossmint_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 adopting freezed or json_serializable codegen, with clear re-evaluation triggers.
  • Added CrossmintChain enum to crossmint_core — typed, environment-aware chain validation covering all 24 mainnet chains, 20 testnet chains, Solana, and Stellar. Includes fromApiValue() / tryFromApiValue() for safe parsing and validateForEnvironment() 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; calling signMessage() or signTransaction() locally throws a descriptive error.
  • Added CrossmintPasskeySignerConfig model and crossmintGuardAgainstPasskeySigners() 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 CrossmintApiKeySignerConfig and CrossmintPasskeySignerConfig to the CrossmintSignerConfig sealed hierarchy in crossmint_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 bs58 package. The _decodeBase58() and _encodeBase58() helpers in crossmint_non_custodial_signer.dart now delegate to base58.decode() and base58.encode().
  • Upgraded chain-type detection helpers (crossmintIsSolanaChain(), crossmintIsStellarChain(), _isSolanaChain()) to prefer enum-based matching via CrossmintChain.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.orderId response shape returned by POST /api/2022-06-09/orders.
  • Fixed scripts/dart_defines_from_env.sh so JSON-valued Dart defines work with direct command substitution in the documented flutter 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 drive and 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_flutter and 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.