Overview
The Dynamic Flutter SDK provides a comprehensive API for building Web3-enabled Flutter applications. This reference documents all the modules, functions, and types available in the SDK.Requirements
- Flutter 3.0+
- Dart 3.0+
- iOS 13.0+ / Android API Level 26+
Installation
Copy
Ask AI
# pubspec.yaml
dependencies:
dynamic_sdk: ^VERSION
SDK Architecture
The SDK uses a singleton pattern with modular access to different functionalities:Copy
Ask AI
import 'package:dynamic_sdk/dynamic_sdk.dart';
// Initialize at app launch (in main.dart)
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await DynamicSDK.instance.initialize(
environmentId: 'YOUR_ENV_ID',
);
runApp(MyApp());
}
// Access SDK instance
final sdk = DynamicSDK.instance;
// Access modules
sdk.auth // Authentication
sdk.wallets // Wallet management
sdk.evm // EVM chain operations
sdk.solana // Solana operations
sdk.networks // Available networks
sdk.mfa // Multi-factor authentication
sdk.passkeys // Passkey management
sdk.ui // Built-in UI components
Core Modules
Initialization
Copy
Ask AI
// Initialize SDK (call once at app launch)
await DynamicSDK.instance.initialize(
environmentId: 'YOUR_ENV_ID',
);
// Get SDK instance
final sdk = DynamicSDK.instance;
Authentication (sdk.auth)
Copy
Ask AI
// Current user
final user = sdk.auth.authenticatedUser;
// Auth token
final token = sdk.auth.token;
// Reactive streams
sdk.auth.authenticatedUserChanges // Stream<UserProfile?>
sdk.auth.tokenChanges // Stream<String?>
// Logout
await sdk.auth.logout();
// Email OTP
await sdk.auth.email.sendOTP('[email protected]');
await sdk.auth.email.verifyOTP('123456');
await sdk.auth.email.resendOTP();
// SMS OTP
final phoneData = PhoneData(
dialCode: '+1',
iso2: 'US',
phone: '5551234567',
);
await sdk.auth.sms.sendOTP(phoneData);
await sdk.auth.sms.verifyOTP('123456');
await sdk.auth.sms.resendOTP();
// Social authentication
await sdk.auth.social.connect(SocialProvider.google);
await sdk.auth.social.connect(SocialProvider.apple);
await sdk.auth.social.connect(SocialProvider.farcaster);
// Passkey authentication
await sdk.auth.passkey.signIn();
// External JWT
await sdk.auth.externalAuth.signInWithExternalJwt(
jwt: 'your-jwt',
);
Wallets (sdk.wallets)
Copy
Ask AI
// Current wallets
final wallets = sdk.wallets.userWallets; // List<BaseWallet>
// Reactive stream
sdk.wallets.userWalletsChanges // Stream<List<BaseWallet>>
// Get balance
final balance = await sdk.wallets.getBalance(wallet);
// Get current network
final network = await sdk.wallets.getNetwork(wallet);
// Switch network
await sdk.wallets.switchNetwork(wallet, targetNetwork);
// Set primary wallet
await sdk.wallets.setPrimary(walletId);
// Sign message
final signature = await sdk.wallets.signMessage(wallet, 'Hello');
// Sign typed data (EIP-712)
final signature = await sdk.wallets.signTypedData(wallet, typedDataJson);
// Verify signature
final isValid = await sdk.wallets.verifySignature(
wallet: wallet,
message: 'Hello',
signature: signature,
);
EVM Operations (sdk.evm)
Copy
Ask AI
// Create public client for chain
final client = sdk.evm.createPublicClient(chainId: 1);
// Get gas price
final gasPrice = await client.getGasPrice();
// Send transaction
final transaction = EthereumTransaction(
to: '0x...',
value: '1000000000000000', // Wei as String
gasLimit: 21000,
maxFeePerGas: gasPrice.maxFeePerGas,
maxPriorityFeePerGas: gasPrice.maxPriorityFeePerGas,
);
final txHash = await sdk.evm.sendTransaction(wallet, transaction);
// Sign transaction (without sending)
final signedTx = await sdk.evm.signTransaction(wallet, transaction);
// Write to contract
final input = WriteContractInput(
address: '0x...',
functionName: 'transfer',
args: [recipient, amount],
abi: [/* ABI maps */],
);
final txHash = await sdk.evm.writeContract(wallet, input);
Solana Operations (sdk.solana)
Copy
Ask AI
// Create connection
final connection = sdk.solana.createConnection();
// Get latest blockhash
final blockhashResult = await connection.getLatestBlockhash();
final blockhash = blockhashResult.blockhash;
// Create signer
final signer = sdk.solana.createSigner(wallet);
// Sign message
final signature = await signer.signMessage('Hello');
// Sign transaction
final signedTx = await signer.signEncodedTransaction(base64Transaction);
// Sign and send transaction
final signature = await signer.signAndSendEncodedTransaction(base64Transaction);
Networks (sdk.networks)
Copy
Ask AI
// Available EVM networks
final evmNetworks = sdk.networks.evm; // List<GenericNetwork>
// Available Solana networks
final solanaNetworks = sdk.networks.solana; // List<GenericNetwork>
// Network properties
network.name // String
network.chainId // For EVM
network.networkId // For Solana
MFA (sdk.mfa)
Copy
Ask AI
// Get user devices
final devices = await sdk.mfa.getUserDevices();
// Add TOTP device (returns MfaAddDevice with secret)
final device = await sdk.mfa.addDevice('totp');
// Verify device
await sdk.mfa.verifyDevice('123456', 'totp');
// Authenticate device to get MFA token
final token = await sdk.mfa.authenticateDevice(
code: '123456',
deviceId: deviceId,
createMfaToken: MfaCreateToken(singleUse: true),
);
// Delete device (requires MFA token)
await sdk.mfa.deleteUserDevice(deviceId, mfaAuthToken: token);
// Recovery codes
final codes = await sdk.mfa.getRecoveryCodes(generateNewCodes: false);
await sdk.mfa.acknowledgeRecoveryCodes(); // Mark codes as shown to user
await sdk.mfa.authenticateRecoveryCode(recoveryCode);
Passkeys (sdk.passkeys)
Copy
Ask AI
// Get user's passkeys
final passkeys = await sdk.passkeys.getPasskeys();
// Register new passkey
await sdk.passkeys.registerPasskey();
// Authenticate with passkey for MFA
final response = await sdk.passkeys.authenticatePasskeyMFA(
createMfaToken: MfaCreateToken(singleUse: true),
relatedOriginRpId: null,
);
// Delete passkey
await sdk.passkeys.deletePasskey(
passkeyId: passkeyId,
);
// Passkey properties
passkey.id // String - Unique identifier
passkey.createdAt // String - Creation timestamp (ISO format)
passkey.lastUsedAt // String? - Last authentication time
passkey.isDefault // bool? - Whether this is the default passkey
Built-in UI (sdk.ui)
Copy
Ask AI
// Show authentication UI
await sdk.ui.showAuth();
// Show user profile
await sdk.ui.showUserProfile();
Data Types
DynamicSDKConfig
Copy
Ask AI
// Configuration is passed to initialize method
await DynamicSDK.instance.initialize(
environmentId: 'YOUR_ENV_ID', // Required
);
BaseWallet
Copy
Ask AI
class BaseWallet {
final String address; // Wallet address
final String chain; // "EVM" or "SOL"
final String? walletName; // Wallet name
final String? id; // Wallet ID for API operations
}
UserProfile
Copy
Ask AI
class UserProfile {
final String? userId;
final String? email;
final String? phoneNumber;
// Additional properties available
}
PhoneData
Copy
Ask AI
class PhoneData {
final String dialCode; // e.g., "+1"
final String iso2; // e.g., "US"
final String phone; // Phone number without country code
}
WriteContractInput
Copy
Ask AI
class WriteContractInput {
final String address;
final String functionName;
final List<dynamic> args;
final List<Map<String, dynamic>> abi;
}
GenericNetwork
Copy
Ask AI
class GenericNetwork {
final String name;
final int? chainId; // For EVM networks
final String? networkId; // For Solana networks
}
Error Handling
All SDK functions can throw exceptions. Use Dart’s native error handling:Copy
Ask AI
try {
await sdk.auth.email.verifyOTP(code);
} catch (e) {
print('Error: $e');
}
Copy
Ask AI
try {
await sdk.auth.email.sendOTP(email);
} catch (e) {
setState(() {
errorMessage = 'Failed: $e';
});
}
Quick Reference Example
Copy
Ask AI
import 'package:flutter/material.dart';
import 'package:dynamic_sdk/dynamic_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await DynamicSDK.instance.initialize(
environmentId: 'YOUR_ENV_ID',
);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Dynamic SDK Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final sdk = DynamicSDK.instance;
bool isAuthenticated = false;
@override
void initState() {
super.initState();
// Check initial auth state
isAuthenticated = sdk.auth.authenticatedUser != null;
// Listen to auth changes
sdk.auth.authenticatedUserChanges.listen((user) {
setState(() {
isAuthenticated = user != null;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dynamic SDK Demo'),
),
body: Center(
child: isAuthenticated ? HomeScreen() : LoginScreen(),
),
);
}
}
class LoginScreen extends StatelessWidget {
final sdk = DynamicSDK.instance;
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
try {
await sdk.ui.showAuth();
} catch (e) {
print('Login failed: $e');
}
},
child: Text('Sign In'),
);
}
}
class HomeScreen extends StatelessWidget {
final sdk = DynamicSDK.instance;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Welcome!'),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
try {
await sdk.ui.showUserProfile();
} catch (e) {
print('Error: $e');
}
},
child: Text('View Profile'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
try {
await sdk.auth.logout();
} catch (e) {
print('Logout failed: $e');
}
},
child: Text('Logout'),
),
],
);
}
}
Session State Management with StreamBuilder
For production apps, use StreamBuilder for reactive state management:Copy
Ask AI
import 'package:flutter/material.dart';
import 'package:dynamic_sdk/dynamic_sdk.dart';
class AppContent extends StatelessWidget {
final sdk = DynamicSDK.instance;
@override
Widget build(BuildContext context) {
return StreamBuilder<UserProfile?>(
stream: sdk.auth.authenticatedUserChanges,
initialData: sdk.auth.authenticatedUser,
builder: (context, snapshot) {
final isAuthenticated = snapshot.data != null;
if (isAuthenticated) {
return HomeScreen();
} else {
return LoginScreen();
}
},
);
}
}
// Wallet management with StreamBuilder
class WalletList extends StatelessWidget {
final sdk = DynamicSDK.instance;
@override
Widget build(BuildContext context) {
return StreamBuilder<List<BaseWallet>>(
stream: sdk.wallets.userWalletsChanges,
initialData: sdk.wallets.userWallets,
builder: (context, snapshot) {
final wallets = snapshot.data ?? [];
if (wallets.isEmpty) {
return Text('No wallets found');
}
return ListView.builder(
itemCount: wallets.length,
itemBuilder: (context, index) {
final wallet = wallets[index];
return ListTile(
title: Text(wallet.address),
subtitle: Text(wallet.chain),
trailing: Text(wallet.walletName ?? 'Unknown'),
);
},
);
},
);
}
}
Using FutureBuilder for Async Operations
Copy
Ask AI
class WalletBalance extends StatelessWidget {
final BaseWallet wallet;
final sdk = DynamicSDK.instance;
WalletBalance({required this.wallet});
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: sdk.wallets.getBalance(wallet),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return Text('Balance: ${snapshot.data}');
},
);
}
}
Complete Example App: For a fully functional Flutter app demonstrating all SDK
features, check the example directory in the dynamic_sdk package for complete
implementation examples.