Skip to main content

Configuration

DynamicSDK Initialization

Configuration for initializing the Dynamic SDK.
await DynamicSDK.instance.initialize(
  environmentId: 'YOUR_ENV_ID',  // Your Dynamic environment ID (required)
);

Parameters

  • environmentId (String) - Your Dynamic environment ID (required)

Example

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await DynamicSDK.instance.initialize(
    environmentId: 'YOUR_ENV_ID',
  );

  runApp(MyApp());
}

Authentication

UserProfile

Represents an authenticated user’s profile.
class UserProfile {
  final String? userId;
  final String? email;
  final String? phoneNumber;
  // Additional fields available
}

Properties

  • userId (String?) - Unique user identifier
  • email (String?) - User’s email address
  • phoneNumber (String?) - User’s phone number

Example

final user = sdk.auth.authenticatedUser;
if (user != null) {
  print('User ID: ${user.userId}');
  print('Email: ${user.email}');
  print('Phone: ${user.phoneNumber}');
}

StreamBuilder Example

StreamBuilder<UserProfile?>(
  stream: sdk.auth.authenticatedUserChanges,
  initialData: sdk.auth.authenticatedUser,
  builder: (context, snapshot) {
    final user = snapshot.data;
    if (user == null) {
      return Text('Not logged in');
    }
    return Column(
      children: [
        Text('User ID: ${user.userId}'),
        if (user.email != null) Text('Email: ${user.email}'),
        if (user.phoneNumber != null) Text('Phone: ${user.phoneNumber}'),
      ],
    );
  },
)

PhoneData

Phone number data for SMS authentication.
class PhoneData {
  final String dialCode;   // e.g., "+1"
  final String iso2;       // e.g., "US"
  final String phone;      // Phone number without country code
}

Properties

  • dialCode (String) - Country dial code with + prefix
  • iso2 (String) - ISO 3166-1 alpha-2 country code
  • phone (String) - Phone number without country code

Example

final phoneData = PhoneData(
  dialCode: '+1',
  iso2: 'US',
  phone: '5551234567',
);

await sdk.auth.sms.sendOTP(phoneData);

Country Code Examples

// United States
PhoneData(dialCode: '+1', iso2: 'US', phone: '5551234567')

// United Kingdom
PhoneData(dialCode: '+44', iso2: 'GB', phone: '7700900123')

// India
PhoneData(dialCode: '+91', iso2: 'IN', phone: '9876543210')

// Japan
PhoneData(dialCode: '+81', iso2: 'JP', phone: '9012345678')

SocialProvider

Enum for social authentication providers.
enum SocialProvider {
  google,
  apple,
  farcaster,
}

Example

// Google sign-in
await sdk.auth.social.connect(SocialProvider.google);

// Apple sign-in
await sdk.auth.social.connect(SocialProvider.apple);

// Farcaster sign-in
await sdk.auth.social.connect(SocialProvider.farcaster);

Wallets

BaseWallet

Represents a user’s wallet.
class BaseWallet {
  final String address;        // Wallet address
  final String chain;          // "EVM" or "SOL"
  final String? walletName;    // Wallet name (optional)
  final String? id;            // Wallet ID for API operations (optional)
}

Properties

  • address (String) - The wallet’s public address
  • chain (String) - Blockchain type: “EVM” for Ethereum-compatible chains or “SOL” for Solana
  • walletName (String?) - Human-readable name of the wallet provider (e.g., “MetaMask”, “Phantom”)
  • id (String?) - Unique identifier for API operations like setPrimary

Example

final wallets = sdk.wallets.userWallets;
for (final wallet in wallets) {
  print('Address: ${wallet.address}');
  print('Chain: ${wallet.chain}');
  print('Name: ${wallet.walletName}');
  print('ID: ${wallet.id}');
}

Checking Wallet Type

final wallet = sdk.wallets.userWallets.first;

if (wallet.chain == 'EVM') {
  // This is an Ethereum-compatible wallet
  final client = sdk.evm.createPublicClient(chainId: 1);
  // Perform EVM operations
} else if (wallet.chain == 'SOL') {
  // This is a Solana wallet
  final connection = sdk.solana.createConnection();
  // Perform Solana operations
}

Widget Example

class WalletCard extends StatelessWidget {
  final BaseWallet wallet;

  WalletCard({required this.wallet});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        leading: Icon(
          wallet.chain == 'EVM' ? Icons.link : Icons.circle,
        ),
        title: Text(
          wallet.address.length > 20
              ? '${wallet.address.substring(0, 10)}...${wallet.address.substring(wallet.address.length - 8)}'
              : wallet.address,
        ),
        subtitle: Text('${wallet.chain} - ${wallet.walletName ?? "Unknown"}'),
        trailing: wallet.id != null
            ? IconButton(
                icon: Icon(Icons.star_border),
                onPressed: () async {
                  await sdk.wallets.setPrimary(wallet.id!);
                },
              )
            : null,
      ),
    );
  }
}

GenericNetwork

Represents a blockchain network.
class GenericNetwork {
  final String name;
  final int? chainId;      // For EVM networks
  final String? networkId; // For Solana networks
}

Properties

  • name (String) - Human-readable network name
  • chainId (int?) - Chain ID for EVM networks (null for Solana)
  • networkId (String?) - Network ID for Solana networks (null for EVM)

Example

// EVM networks
final evmNetworks = sdk.networks.evm;
final ethereum = evmNetworks.firstWhere((n) => n.chainId == 1);
print('Network: ${ethereum.name}, Chain ID: ${ethereum.chainId}');

// Solana networks
final solanaNetworks = sdk.networks.solana;
final mainnet = solanaNetworks.firstWhere((n) => n.networkId == 'mainnet-beta');
print('Network: ${mainnet.name}, Network ID: ${mainnet.networkId}');

Common EVM Chain IDs

// Ethereum Mainnet
GenericNetwork(name: 'Ethereum', chainId: 1, networkId: null)

// Polygon
GenericNetwork(name: 'Polygon', chainId: 137, networkId: null)

// Arbitrum
GenericNetwork(name: 'Arbitrum', chainId: 42161, networkId: null)

// Optimism
GenericNetwork(name: 'Optimism', chainId: 10, networkId: null)

// Base
GenericNetwork(name: 'Base', chainId: 8453, networkId: null)

Common Solana Network IDs

// Mainnet
GenericNetwork(name: 'Mainnet', chainId: null, networkId: 'mainnet-beta')

// Devnet
GenericNetwork(name: 'Devnet', chainId: null, networkId: 'devnet')

// Testnet
GenericNetwork(name: 'Testnet', chainId: null, networkId: 'testnet')

EVM / Blockchain

EthereumTransaction

Transaction data for EVM chains.
class EthereumTransaction {
  final String to;                     // Recipient address
  final String value;                  // Amount in Wei (as String)
  final int gasLimit;                  // Gas limit
  final int? maxFeePerGas;             // Max fee per gas (optional)
  final int? maxPriorityFeePerGas;     // Priority fee (optional)
  final String? data;                  // Contract data (optional)
}

Properties

  • to (String) - Recipient address (0x prefixed hex string)
  • value (String) - Amount to send in Wei (as String to handle large numbers)
  • gasLimit (int) - Maximum gas units allowed for the transaction
  • maxFeePerGas (int?) - Maximum total fee per gas unit (optional, for EIP-1559)
  • maxPriorityFeePerGas (int?) - Maximum priority fee per gas unit (optional, for EIP-1559)
  • data (String?) - Encoded contract call data (optional)

Example

final transaction = EthereumTransaction(
  to: '0x1234567890123456789012345678901234567890',
  value: '1000000000000000', // 0.001 ETH in Wei
  gasLimit: 21000,
  maxFeePerGas: 30000000000,
  maxPriorityFeePerGas: 2000000000,
);

Converting ETH to Wei

// Helper function to convert ETH to Wei
String ethToWei(double eth) {
  final wei = (eth * 1e18).toStringAsFixed(0);
  return wei;
}

// Usage
final transaction = EthereumTransaction(
  to: recipientAddress,
  value: ethToWei(0.001), // 0.001 ETH
  gasLimit: 21000,
);

WriteContractInput

Input for writing to a smart contract.
class WriteContractInput {
  final String address;                      // Contract address
  final String functionName;                 // Function to call
  final List<dynamic> args;                  // Function arguments
  final List<Map<String, dynamic>> abi;      // Contract ABI
}

Properties

  • address (String) - Smart contract address
  • functionName (String) - Name of the function to call
  • args (List<dynamic>) - Function arguments in order
  • abi (List<Map<String, dynamic>>) - Contract ABI definition

Example

final input = WriteContractInput(
  address: '0x...',
  functionName: 'transfer',
  args: ['0x...', '1000000000000000000'], // recipient, amount
  abi: [
    {
      'inputs': [
        {'name': 'recipient', 'type': 'address'},
        {'name': 'amount', 'type': 'uint256'},
      ],
      'name': 'transfer',
      'outputs': [
        {'name': '', 'type': 'bool'},
      ],
      'stateMutability': 'nonpayable',
      'type': 'function',
    },
  ],
);

ERC20 Transfer Example

class Erc20Helper {
  static const transferAbi = [
    {
      'inputs': [
        {'name': 'recipient', 'type': 'address'},
        {'name': 'amount', 'type': 'uint256'},
      ],
      'name': 'transfer',
      'outputs': [
        {'name': '', 'type': 'bool'},
      ],
      'stateMutability': 'nonpayable',
      'type': 'function',
    },
  ];

  static WriteContractInput createTransfer({
    required String tokenAddress,
    required String recipient,
    required String amount,
  }) {
    return WriteContractInput(
      address: tokenAddress,
      functionName: 'transfer',
      args: [recipient, amount],
      abi: transferAbi,
    );
  }
}

// Usage
final input = Erc20Helper.createTransfer(
  tokenAddress: '0x...',
  recipient: '0x...',
  amount: '1000000000000000000', // 1 token with 18 decimals
);

GasPrice

Current gas price information for EVM chains.
class GasPrice {
  final int maxFeePerGas;
  final int maxPriorityFeePerGas;
}

Properties

  • maxFeePerGas (int) - Maximum total fee per gas unit (in Wei)
  • maxPriorityFeePerGas (int) - Maximum priority fee per gas unit (in Wei)

Example

final client = sdk.evm.createPublicClient(chainId: 1);
final gasPrice = await client.getGasPrice();
print('Max fee: ${gasPrice.maxFeePerGas}');
print('Priority fee: ${gasPrice.maxPriorityFeePerGas}');

Converting Gas Price to Gwei

double weiToGwei(int wei) {
  return wei / 1e9;
}

// Usage
final gasPrice = await client.getGasPrice();
print('Max fee: ${weiToGwei(gasPrice.maxFeePerGas)} Gwei');
print('Priority fee: ${weiToGwei(gasPrice.maxPriorityFeePerGas)} Gwei');

BlockhashResult

Solana blockhash information.
class BlockhashResult {
  final String blockhash;
  final int lastValidBlockHeight;
}

Properties

  • blockhash (String) - Recent blockhash for transaction creation
  • lastValidBlockHeight (int) - Last block height at which the blockhash is valid

Example

final connection = sdk.solana.createConnection();
final result = await connection.getLatestBlockhash();
print('Blockhash: ${result.blockhash}');
print('Valid until block: ${result.lastValidBlockHeight}');

MFA

MfaDevice

Represents an MFA device.
class MfaDevice {
  final String? id;
  final MfaDeviceType? type;
}

enum MfaDeviceType {
  totp,
}

Properties

  • id (String?) - Unique device identifier
  • type (MfaDeviceType?) - Type of MFA device (currently only TOTP)

Example

final devices = await sdk.mfa.getUserDevices();
for (final device in devices) {
  print('Device ID: ${device.id}');
  print('Type: ${device.type?.name}');
}

MfaAddDevice

Response when adding an MFA device.
class MfaAddDevice {
  final String secret;     // Secret for QR code generation
  final String? id;
}

Properties

  • secret (String) - Secret key for TOTP QR code generation
  • id (String?) - Device identifier

Example

final device = await sdk.mfa.addDevice('totp');
print('Secret for QR code: ${device.secret}');

// Generate QR code with the secret
// Format: otpauth://totp/YourApp:[email protected]?secret=${device.secret}&issuer=YourApp
final qrData = 'otpauth://totp/MyApp:[email protected]?secret=${device.secret}&issuer=MyApp';

QR Code Generation Example

import 'package:qr_flutter/qr_flutter.dart';

class MfaQrCode extends StatelessWidget {
  final MfaAddDevice device;
  final String userEmail;

  MfaQrCode({required this.device, required this.userEmail});

  @override
  Widget build(BuildContext context) {
    final qrData = 'otpauth://totp/MyApp:$userEmail?secret=${device.secret}&issuer=MyApp';

    return Column(
      children: [
        QrImageView(
          data: qrData,
          version: QrVersions.auto,
          size: 200.0,
        ),
        SizedBox(height: 16),
        Text('Scan with your authenticator app'),
        SizedBox(height: 8),
        SelectableText(
          device.secret,
          style: TextStyle(fontFamily: 'monospace'),
        ),
      ],
    );
  }
}

MfaCreateToken

Parameters for MFA token creation.
class MfaCreateToken {
  final bool singleUse;
}

Properties

  • singleUse (bool) - Whether the token should be single-use

Example

final createToken = MfaCreateToken(singleUse: true);

final token = await sdk.mfa.authenticateDevice(
  code: '123456',
  deviceId: deviceId,
  createMfaToken: createToken,
);

Passkeys

UserPasskey

Represents a user’s passkey.
class UserPasskey {
  final String id;
  final String createdAt;      // ISO format
  final String? lastUsedAt;    // ISO format (optional)
  final bool? isDefault;
}

Properties

  • id (String) - Unique passkey identifier
  • createdAt (String) - Creation timestamp in ISO 8601 format
  • lastUsedAt (String?) - Last usage timestamp in ISO 8601 format (optional)
  • isDefault (bool?) - Whether this is the default passkey

Example

final passkeys = await sdk.passkeys.getPasskeys();
for (final passkey in passkeys) {
  print('ID: ${passkey.id}');
  print('Created: ${passkey.createdAt}');
  print('Last used: ${passkey.lastUsedAt}');
  print('Is default: ${passkey.isDefault}');
}

Formatting Timestamps

import 'package:intl/intl.dart';

String formatPasskeyDate(String isoDate) {
  final date = DateTime.parse(isoDate);
  final formatter = DateFormat('MMM dd, yyyy HH:mm');
  return formatter.format(date);
}

// Usage
final passkey = passkeys.first;
print('Created: ${formatPasskeyDate(passkey.createdAt)}');
if (passkey.lastUsedAt != null) {
  print('Last used: ${formatPasskeyDate(passkey.lastUsedAt!)}');
}

Widget Example

class PasskeyListItem extends StatelessWidget {
  final UserPasskey passkey;
  final VoidCallback onDelete;

  PasskeyListItem({required this.passkey, required this.onDelete});

  String formatDate(String isoDate) {
    final date = DateTime.parse(isoDate);
    final formatter = DateFormat('MMM dd, yyyy');
    return formatter.format(date);
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        leading: Icon(
          Icons.fingerprint,
          color: passkey.isDefault == true ? Colors.blue : Colors.grey,
        ),
        title: Text('Passkey ${passkey.id.substring(0, 8)}...'),
        subtitle: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Created: ${formatDate(passkey.createdAt)}'),
            if (passkey.lastUsedAt != null)
              Text('Last used: ${formatDate(passkey.lastUsedAt!)}'),
            if (passkey.isDefault == true)
              Text(
                'Default',
                style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
              ),
          ],
        ),
        trailing: IconButton(
          icon: Icon(Icons.delete),
          onPressed: onDelete,
        ),
      ),
    );
  }
}

PasskeyAuthenticationResponse

Response from passkey MFA authentication.
class PasskeyAuthenticationResponse {
  final String? jwt;    // MFA token
}

Properties

  • jwt (String?) - JWT token for MFA operations

Example

final response = await sdk.passkeys.authenticatePasskeyMFA(
  createMfaToken: MfaCreateToken(singleUse: true),
  relatedOriginRpId: null,
);
print('MFA Token: ${response.jwt}');

Error Handling

All SDK methods that can fail will throw exceptions. Use standard Dart error handling:
try {
  await sdk.auth.email.verifyOTP(code);
} catch (e) {
  print('Error: $e');
}
For async operations in widgets:
Future<void> performOperation() async {
  try {
    final wallets = sdk.wallets.userWallets;
    // Process wallets
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Failed: $e')),
    );
  }
}

Common Error Patterns

class ErrorHandler {
  static void handle(BuildContext context, dynamic error) {
    String message = 'An error occurred';

    if (error is TimeoutException) {
      message = 'Request timed out';
    } else if (error is FormatException) {
      message = 'Invalid data format';
    } else if (error.toString().contains('network')) {
      message = 'Network error';
    } else if (error.toString().contains('auth')) {
      message = 'Authentication failed';
    }

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        backgroundColor: Colors.red,
      ),
    );
  }
}

// Usage
try {
  await sdk.auth.email.verifyOTP(code);
} catch (e) {
  ErrorHandler.handle(context, e);
}