Wallet Access
userWallets
Get the current list of user wallets (synchronous).Copy
Ask AI
List<BaseWallet> get userWallets
Example
Copy
Ask AI
final wallets = sdk.wallets.userWallets;
for (final wallet in wallets) {
print('${wallet.address} (${wallet.chain})');
}
userWalletsChanges
Observe wallet list changes (reactive stream).Copy
Ask AI
Stream<List<BaseWallet>> get userWalletsChanges
Example
Copy
Ask AI
sdk.wallets.userWalletsChanges.listen((wallets) {
// Handle wallet changes
setState(() {
this.wallets = wallets;
});
});
StreamBuilder Example
Copy
Ask AI
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'),
);
},
);
},
)
Balance Operations
getBalance
Get the balance for a specific wallet.Copy
Ask AI
Future<String> getBalance(BaseWallet wallet)
Parameters
- wallet (BaseWallet) - The wallet to check balance for
Returns
- String - Balance as a string (in native token units)
Example
Copy
Ask AI
try {
final balance = await sdk.wallets.getBalance(wallet);
print('Balance: $balance');
} catch (e) {
print('Failed to get balance: $e');
}
FutureBuilder Example
Copy
Ask AI
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}');
},
)
Network Operations
getNetwork
Get the current network for a wallet.Copy
Ask AI
Future<GenericNetwork> getNetwork(BaseWallet wallet)
Parameters
- wallet (BaseWallet) - The wallet to get network for
Returns
- GenericNetwork - The current network
Example
Copy
Ask AI
try {
final network = await sdk.wallets.getNetwork(wallet);
print('Network: ${network.name}, Chain ID: ${network.chainId}');
} catch (e) {
print('Failed to get network: $e');
}
switchNetwork
Switch a wallet to a different network.Copy
Ask AI
Future<void> switchNetwork(BaseWallet wallet, GenericNetwork network)
Parameters
- wallet (BaseWallet) - The wallet to switch networks for
- network (GenericNetwork) - The target network
Example
Copy
Ask AI
try {
final polygon = sdk.networks.evm.firstWhere((n) => n.chainId == 137);
await sdk.wallets.switchNetwork(wallet, polygon);
print('Switched to ${polygon.name}');
} catch (e) {
print('Failed to switch network: $e');
}
Complete Example with Network Selector
Copy
Ask AI
class NetworkSwitcher extends StatefulWidget {
final BaseWallet wallet;
NetworkSwitcher({required this.wallet});
@override
_NetworkSwitcherState createState() => _NetworkSwitcherState();
}
class _NetworkSwitcherState extends State<NetworkSwitcher> {
final sdk = DynamicSDK.instance;
GenericNetwork? currentNetwork;
bool isLoading = false;
@override
void initState() {
super.initState();
loadCurrentNetwork();
}
Future<void> loadCurrentNetwork() async {
try {
final network = await sdk.wallets.getNetwork(widget.wallet);
setState(() {
currentNetwork = network;
});
} catch (e) {
print('Failed to load network: $e');
}
}
Future<void> switchNetwork(GenericNetwork network) async {
setState(() => isLoading = true);
try {
await sdk.wallets.switchNetwork(widget.wallet, network);
setState(() {
currentNetwork = network;
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Switched to ${network.name}')),
);
} catch (e) {
setState(() => isLoading = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to switch: $e')),
);
}
}
@override
Widget build(BuildContext context) {
final networks = widget.wallet.chain == 'EVM'
? sdk.networks.evm
: sdk.networks.solana;
return Column(
children: [
if (currentNetwork != null)
Text('Current: ${currentNetwork!.name}'),
SizedBox(height: 16),
if (isLoading)
CircularProgressIndicator()
else
DropdownButton<GenericNetwork>(
value: currentNetwork,
items: networks.map((network) {
return DropdownMenuItem(
value: network,
child: Text(network.name),
);
}).toList(),
onChanged: (network) {
if (network != null) {
switchNetwork(network);
}
},
),
],
);
}
}
Message Signing
signMessage
Sign a message with a wallet.Copy
Ask AI
Future<String> signMessage(BaseWallet wallet, String message)
Parameters
- wallet (BaseWallet) - The wallet to sign with
- message (String) - The message to sign
Returns
- String - The signature
Example
Copy
Ask AI
try {
final signature = await sdk.wallets.signMessage(wallet, 'Hello!');
print('Signature: $signature');
} catch (e) {
print('Failed to sign: $e');
}
Complete Example
Copy
Ask AI
class MessageSigner extends StatefulWidget {
final BaseWallet wallet;
MessageSigner({required this.wallet});
@override
_MessageSignerState createState() => _MessageSignerState();
}
class _MessageSignerState extends State<MessageSigner> {
final sdk = DynamicSDK.instance;
final messageController = TextEditingController();
String? signature;
bool isLoading = false;
Future<void> signMessage() async {
setState(() => isLoading = true);
try {
final sig = await sdk.wallets.signMessage(
widget.wallet,
messageController.text,
);
setState(() {
signature = sig;
isLoading = false;
});
} catch (e) {
setState(() => isLoading = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to sign: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: messageController,
decoration: InputDecoration(
labelText: 'Message to sign',
hintText: 'Enter your message',
),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: isLoading ? null : signMessage,
child: isLoading
? CircularProgressIndicator()
: Text('Sign Message'),
),
if (signature != null) ...[
SizedBox(height: 16),
Text('Signature:'),
SelectableText(
signature!,
style: TextStyle(fontSize: 12, fontFamily: 'monospace'),
),
],
],
);
}
@override
void dispose() {
messageController.dispose();
super.dispose();
}
}
Typed Data Signing (EIP-712)
signTypedData
Sign typed data (EIP-712) with a wallet.Copy
Ask AI
Future<String> signTypedData(BaseWallet wallet, String typedDataJson)
Parameters
- wallet (BaseWallet) - The wallet to sign with
- typedDataJson (String) - The typed data as a JSON string
Returns
- String - The signature
Example
Copy
Ask AI
const typedData = '''
{
"types": {
"EIP712Domain": [
{"name": "name", "type": "string"},
{"name": "chainId", "type": "uint256"}
],
"Person": [
{"name": "name", "type": "string"}
]
},
"primaryType": "Person",
"domain": {
"name": "My App",
"chainId": 1
},
"message": {
"name": "Alice"
}
}
''';
try {
final signature = await sdk.wallets.signTypedData(wallet, typedData);
print('Signature: $signature');
} catch (e) {
print('Failed to sign: $e');
}
Complete Example
Copy
Ask AI
class TypedDataSigner extends StatefulWidget {
final BaseWallet wallet;
TypedDataSigner({required this.wallet});
@override
_TypedDataSignerState createState() => _TypedDataSignerState();
}
class _TypedDataSignerState extends State<TypedDataSigner> {
final sdk = DynamicSDK.instance;
String? signature;
bool isLoading = false;
Future<void> signTypedData() async {
setState(() => isLoading = true);
const typedData = '''
{
"types": {
"EIP712Domain": [
{"name": "name", "type": "string"},
{"name": "version", "type": "string"},
{"name": "chainId", "type": "uint256"}
],
"Person": [
{"name": "name", "type": "string"},
{"name": "wallet", "type": "address"}
]
},
"primaryType": "Person",
"domain": {
"name": "My DApp",
"version": "1",
"chainId": 1
},
"message": {
"name": "Alice",
"wallet": "${widget.wallet.address}"
}
}
''';
try {
final sig = await sdk.wallets.signTypedData(widget.wallet, typedData);
setState(() {
signature = sig;
isLoading = false;
});
} catch (e) {
setState(() => isLoading = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to sign: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Sign Typed Data (EIP-712)'),
SizedBox(height: 16),
ElevatedButton(
onPressed: isLoading ? null : signTypedData,
child: isLoading
? CircularProgressIndicator()
: Text('Sign Typed Data'),
),
if (signature != null) ...[
SizedBox(height: 16),
Text('Signature:'),
SelectableText(
signature!,
style: TextStyle(fontSize: 12, fontFamily: 'monospace'),
),
],
],
);
}
}
Signature Verification
verifySignature
Verify a signature against a message and wallet.Copy
Ask AI
Future<bool> verifySignature({
required BaseWallet wallet,
required String message,
required String signature,
})
Parameters
- wallet (BaseWallet) - The wallet that signed the message
- message (String) - The original message
- signature (String) - The signature to verify
Returns
- bool -
trueif signature is valid,falseotherwise
Example
Copy
Ask AI
try {
final message = 'Hello!';
final signature = await sdk.wallets.signMessage(wallet, message);
final isValid = await sdk.wallets.verifySignature(
wallet: wallet,
message: message,
signature: signature,
);
print('Signature is ${isValid ? "valid" : "invalid"}');
} catch (e) {
print('Verification failed: $e');
}
Complete Example
Copy
Ask AI
class SignatureVerifier extends StatefulWidget {
final BaseWallet wallet;
SignatureVerifier({required this.wallet});
@override
_SignatureVerifierState createState() => _SignatureVerifierState();
}
class _SignatureVerifierState extends State<SignatureVerifier> {
final sdk = DynamicSDK.instance;
final messageController = TextEditingController();
final signatureController = TextEditingController();
bool? isValid;
bool isLoading = false;
Future<void> verifySignature() async {
setState(() => isLoading = true);
try {
final valid = await sdk.wallets.verifySignature(
wallet: widget.wallet,
message: messageController.text,
signature: signatureController.text,
);
setState(() {
isValid = valid;
isLoading = false;
});
} catch (e) {
setState(() => isLoading = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Verification failed: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: messageController,
decoration: InputDecoration(
labelText: 'Original message',
hintText: 'Enter the message',
),
),
SizedBox(height: 12),
TextField(
controller: signatureController,
decoration: InputDecoration(
labelText: 'Signature',
hintText: 'Enter the signature',
),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: isLoading ? null : verifySignature,
child: isLoading
? CircularProgressIndicator()
: Text('Verify Signature'),
),
if (isValid != null) ...[
SizedBox(height: 16),
Text(
isValid! ? 'Signature is VALID' : 'Signature is INVALID',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: isValid! ? Colors.green : Colors.red,
),
),
],
],
);
}
@override
void dispose() {
messageController.dispose();
signatureController.dispose();
super.dispose();
}
}
Primary Wallet Management
setPrimary
Set a wallet as the primary wallet for the user.Copy
Ask AI
Future<void> setPrimary(String walletId)
Parameters
- walletId (String) - The ID of the wallet to set as primary
Example
Copy
Ask AI
try {
final walletId = wallet.id;
if (walletId != null) {
await sdk.wallets.setPrimary(walletId);
print('Set wallet as primary');
} else {
print('Wallet ID is null');
}
} catch (e) {
print('Failed to set primary: $e');
}
Complete Example with Wallet List
Copy
Ask AI
class WalletListWithPrimary extends StatefulWidget {
@override
_WalletListWithPrimaryState createState() => _WalletListWithPrimaryState();
}
class _WalletListWithPrimaryState extends State<WalletListWithPrimary> {
final sdk = DynamicSDK.instance;
Future<void> setPrimaryWallet(BaseWallet wallet) async {
final walletId = wallet.id;
if (walletId == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Wallet ID is null')),
);
return;
}
try {
await sdk.wallets.setPrimary(walletId);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Set ${wallet.address} as primary')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to set primary: $e')),
);
}
}
@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 Center(child: Text('No wallets found'));
}
return ListView.builder(
itemCount: wallets.length,
itemBuilder: (context, index) {
final wallet = wallets[index];
return Card(
child: ListTile(
title: Text(wallet.address),
subtitle: Text(
'${wallet.chain} - ${wallet.walletName ?? "Unknown"}',
),
trailing: IconButton(
icon: Icon(Icons.star_border),
onPressed: () => setPrimaryWallet(wallet),
tooltip: 'Set as primary',
),
),
);
},
);
},
);
}
}
Complete Wallet Management Screen
Copy
Ask AI
class WalletManagementScreen extends StatelessWidget {
final sdk = DynamicSDK.instance;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Wallet Management'),
),
body: StreamBuilder<List<BaseWallet>>(
stream: sdk.wallets.userWalletsChanges,
initialData: sdk.wallets.userWallets,
builder: (context, snapshot) {
final wallets = snapshot.data ?? [];
if (wallets.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.wallet, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text('No wallets found'),
],
),
);
}
return ListView.builder(
itemCount: wallets.length,
itemBuilder: (context, index) {
final wallet = wallets[index];
return WalletCard(wallet: wallet);
},
);
},
),
);
}
}
class WalletCard extends StatelessWidget {
final BaseWallet wallet;
final sdk = DynamicSDK.instance;
WalletCard({required this.wallet});
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(8),
child: ExpansionTile(
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"}'),
children: [
Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FutureBuilder<String>(
future: sdk.wallets.getBalance(wallet),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Text('Balance: Loading...');
}
if (snapshot.hasError) {
return Text('Balance: Error');
}
return Text('Balance: ${snapshot.data}');
},
),
SizedBox(height: 8),
FutureBuilder<GenericNetwork>(
future: sdk.wallets.getNetwork(wallet),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Text('Network: Loading...');
}
if (snapshot.hasError) {
return Text('Network: Error');
}
return Text('Network: ${snapshot.data?.name}');
},
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () async {
final walletId = wallet.id;
if (walletId != null) {
try {
await sdk.wallets.setPrimary(walletId);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Set as primary')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed: $e')),
);
}
}
},
child: Text('Set Primary'),
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MessageSigner(wallet: wallet),
),
);
},
child: Text('Sign Message'),
),
],
),
],
),
),
],
),
);
}
}