Skip to main content

Overview

This guide covers how wallets are created and managed with the Dynamic Flutter SDK. Wallets are automatically created for users after authentication when embedded wallets are enabled in your Dynamic dashboard.

Prerequisites

Automatic Wallet Creation

When embedded wallets are enabled, wallets are automatically created for users after they authenticate. You don’t need to manually create wallets - the SDK handles this for you.

Listening for Wallet Creation

Use the userWalletsChanges stream to know when wallets are ready:
import 'dart:async';
import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';

class WalletManager extends ChangeNotifier {
  List<BaseWallet> _wallets = [];
  bool _isCreatingWallets = false;
  bool _creationTimedOut = false;

  StreamSubscription<List<BaseWallet>>? _walletsSub;
  Timer? _timeoutTimer;

  List<BaseWallet> get wallets => _wallets;
  bool get isCreatingWallets => _isCreatingWallets;
  bool get creationTimedOut => _creationTimedOut;

  WalletManager() {
    _initialize();
  }

  void _initialize() {
    // Get current wallets
    _wallets = DynamicSDK.instance.wallets.userWallets;

    // If user is authenticated but no wallets yet, they're being created
    final token = DynamicSDK.instance.auth.token;
    if (token != null && _wallets.isEmpty) {
      _isCreatingWallets = true;

      // Set a timeout for wallet creation
      _timeoutTimer = Timer(const Duration(seconds: 15), () {
        if (_wallets.isEmpty) {
          _isCreatingWallets = false;
          _creationTimedOut = true;
          notifyListeners();
        }
      });
    }

    // Listen for wallet updates
    _walletsSub = DynamicSDK.instance.wallets.userWalletsChanges.listen((newWallets) {
      _wallets = newWallets;

      if (newWallets.isNotEmpty) {
        _isCreatingWallets = false;
        _creationTimedOut = false;
        _timeoutTimer?.cancel();
      }

      notifyListeners();
    });
  }

  @override
  void dispose() {
    _walletsSub?.cancel();
    _timeoutTimer?.cancel();
    super.dispose();
  }
}

Displaying Wallets

import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class WalletsView extends StatelessWidget {
  const WalletsView({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => WalletManager(),
      child: Consumer<WalletManager>(
        builder: (context, walletManager, _) {
          if (walletManager.isCreatingWallets) {
            return const Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  CircularProgressIndicator(),
                  SizedBox(height: 16),
                  Text('Creating wallets...'),
                ],
              ),
            );
          }

          if (walletManager.creationTimedOut) {
            return const Center(
              child: Text('Wallet creation timed out. Please try again.'),
            );
          }

          if (walletManager.wallets.isEmpty) {
            return const Center(
              child: Text('No wallets available'),
            );
          }

          return ListView.builder(
            itemCount: walletManager.wallets.length,
            itemBuilder: (context, index) {
              final wallet = walletManager.wallets[index];
              return WalletCard(wallet: wallet);
            },
          );
        },
      ),
    );
  }
}

class WalletCard extends StatelessWidget {
  final BaseWallet wallet;

  const WalletCard({super.key, required this.wallet});

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  wallet.walletName ?? 'Wallet',
                  style: Theme.of(context).textTheme.titleMedium,
                ),
                Container(
                  padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                  decoration: BoxDecoration(
                    color: Colors.blue.withOpacity(0.2),
                    borderRadius: BorderRadius.circular(4),
                  ),
                  child: Text(
                    wallet.chain.toUpperCase(),
                    style: Theme.of(context).textTheme.labelSmall,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 8),
            Text(
              wallet.address,
              style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                    color: Colors.grey[600],
                  ),
              overflow: TextOverflow.ellipsis,
            ),
          ],
        ),
      ),
    );
  }
}

Using StreamBuilder

Alternatively, use StreamBuilder directly without a manager:
import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';

class WalletsStreamView extends StatelessWidget {
  const WalletsStreamView({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<BaseWallet>>(
      stream: DynamicSDK.instance.wallets.userWalletsChanges,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }

        final wallets = snapshot.data ?? [];

        if (wallets.isEmpty) {
          return const Center(
            child: Text('No wallets available'),
          );
        }

        return ListView.builder(
          itemCount: wallets.length,
          itemBuilder: (context, index) {
            final wallet = wallets[index];
            return ListTile(
              title: Text(wallet.walletName ?? 'Wallet'),
              subtitle: Text(wallet.address),
              trailing: Text(wallet.chain.toUpperCase()),
            );
          },
        );
      },
    );
  }
}

Wallet Types

The SDK supports multiple wallet types:

EVM Wallets

For Ethereum and EVM-compatible chains (Polygon, Base, Arbitrum, etc.):
final evmWallets = DynamicSDK.instance.wallets.userWallets
    .where((wallet) => wallet.chain.toUpperCase() == 'EVM')
    .toList();

Solana Wallets

For Solana blockchain:
final solanaWallets = DynamicSDK.instance.wallets.userWallets
    .where((wallet) => wallet.chain.toUpperCase() == 'SOL')
    .toList();

Wallet Properties

Each BaseWallet has the following properties:
final wallet = DynamicSDK.instance.wallets.userWallets.first;

// Wallet address
final address = wallet.address;  // "0x..." for EVM, base58 for Solana

// Chain type
final chain = wallet.chain;  // "EVM" or "SOL"

// Wallet name (optional)
final name = wallet.walletName;  // e.g., "turnkey"

// Wallet ID (for API operations)
final id = wallet.id;  // Used for setPrimary, etc.
For complete wallet management API documentation including all available methods, see the Wallet Management Reference.

Setting Primary Wallet

You can set a wallet as the user’s primary wallet:
import 'package:dynamic_sdk/dynamic_sdk.dart';

Future<void> setPrimaryWallet(BaseWallet wallet) async {
  final walletId = wallet.id;
  if (walletId == null) {
    print('Wallet has no ID');
    return;
  }

  try {
    await DynamicSDK.instance.wallets.setPrimary(walletId: walletId);
    print('Primary wallet set successfully');
  } catch (e) {
    print('Failed to set primary wallet: $e');
  }
}

Multi-Chain Support

When you have both EVM and Solana enabled in your dashboard, users will automatically get wallets for both chains:
import 'package:dynamic_sdk/dynamic_sdk.dart';
import 'package:flutter/material.dart';

class MultiChainWalletsView extends StatelessWidget {
  const MultiChainWalletsView({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<BaseWallet>>(
      stream: DynamicSDK.instance.wallets.userWalletsChanges,
      builder: (context, snapshot) {
        final wallets = snapshot.data ?? [];

        final evmWallets = wallets
            .where((w) => w.chain.toUpperCase() == 'EVM')
            .toList();

        final solanaWallets = wallets
            .where((w) => w.chain.toUpperCase() == 'SOL')
            .toList();

        return ListView(
          children: [
            if (evmWallets.isNotEmpty) ...[
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: Text(
                  'EVM Wallets',
                  style: Theme.of(context).textTheme.titleLarge,
                ),
              ),
              ...evmWallets.map((wallet) => WalletCard(wallet: wallet)),
            ],
            if (solanaWallets.isNotEmpty) ...[
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: Text(
                  'Solana Wallets',
                  style: Theme.of(context).textTheme.titleLarge,
                ),
              ),
              ...solanaWallets.map((wallet) => WalletCard(wallet: wallet)),
            ],
          ],
        );
      },
    );
  }
}

Manual Wallet Access

You can also access wallets directly without streams:
import 'package:dynamic_sdk/dynamic_sdk.dart';

// Get current wallets
final wallets = DynamicSDK.instance.wallets.userWallets;

if (wallets.isEmpty) {
  print('No wallets available');
} else {
  print('User has ${wallets.length} wallet(s)');

  for (final wallet in wallets) {
    print('${wallet.chain}: ${wallet.address}');
  }
}

Dashboard Configuration

To enable embedded wallets:
  1. Go to your Dynamic Dashboard
  2. Navigate to Wallets settings
  3. Toggle “Embedded Wallets” on
  4. Select the chains you want to support:
    • Enable “EVM” for Ethereum and compatible chains
    • Enable “Solana” for Solana blockchain
  5. Save your changes

Next Steps

After wallets are created, you can:

Reference

For more details on wallet management: