kalp_dlt_wallet 1.0.2
kalp_dlt_wallet: ^1.0.2 copied to clipboard
A Flutter package for interacting with distributed ledger technology (DLT) through the Kalp wallet system.
example/lib/main.dart
import 'dart:developer';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:kalp_dlt_wallet/kalp_dlt_wallet.dart';
// Import method options
enum ImportMethod { seedWords, privateKey }
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Kalp DLT Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
useMaterial3: true,
),
home: const MyHomePage(title: 'Kalp DLT Example'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _apiKeyController = TextEditingController();
late KalpDLTWallet kalpDlt;
KalpWallet wallet = KalpWallet.empty();
String? _seedWords;
final TextEditingController _customSeedController = TextEditingController();
final TextEditingController _privateKeyController = TextEditingController();
bool _useCustomSeeds = false;
ImportMethod _importMethod = ImportMethod.seedWords;
// Added state variables to store operation results
String? _readResult;
String? _writeResult;
String? _gasFeesResult;
// Loading state variables
bool _isGeneratingSeeds = false;
bool _isCreatingWallet = false;
bool _isImportingWallet = false;
bool _isReading = false;
bool _isWriting = false;
bool _isLoadingGasFees = false;
bool get _isApiKeyPresent => _apiKeyController.text.trim().isNotEmpty;
final _nglChannleName = 'YourNGLChannelName';
final _gatewayChannelName = 'YourGatewayChannelName';
static final _nglBaseUrl = 'YourNGLBaseUrl';
static final _gatewayBaseUrl = 'YourGatewayBaseUrl';
@override
void initState() {
super.initState();
// Initialize with empty API key initially
kalpDlt = KalpDLTWallet.initialize(
apiKey: '',
nglBaseUrl: _nglBaseUrl,
gatewayBaseUrl: _gatewayBaseUrl,
);
// Listen to changes in API key
_apiKeyController.addListener(_updateKalpDLT);
}
void _updateKalpDLT() {
kalpDlt = KalpDLTWallet.initialize(
apiKey: _apiKeyController.text,
nglBaseUrl: _nglBaseUrl,
gatewayBaseUrl: _gatewayBaseUrl,
);
}
@override
void dispose() {
_apiKeyController.removeListener(_updateKalpDLT);
_apiKeyController.dispose();
_customSeedController.dispose();
_privateKeyController.dispose();
super.dispose();
}
Future<void> _generateSeedWords() async {
if (_isGeneratingSeeds || !_isApiKeyPresent) {
if (!_isApiKeyPresent) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter an API key first')),
);
}
return;
}
setState(() {
_isGeneratingSeeds = true;
});
try {
await kalpDlt.createSeedWords();
if (mounted) {
setState(() {
_seedWords = KalpDLTWallet.lastGeneratedSeeds;
});
}
} catch (e) {
if (mounted) {
SnackBar snackBar = SnackBar(content: Text(e.toString()));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
} finally {
if (mounted) {
setState(() {
_isGeneratingSeeds = false;
});
}
}
}
Future<void> _createWallet() async {
if (_isCreatingWallet || !_isApiKeyPresent) {
if (!_isApiKeyPresent) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter an API key first')),
);
}
return;
}
setState(() {
_isCreatingWallet = true;
});
try {
await kalpDlt.createWalletWithSeedWords(
channelName: _nglChannleName,
seedWords: KalpDLTWallet.lastGeneratedSeeds?.split(' ') ?? [],
errorCallback: (dynamic e) {
setState(() {
_isCreatingWallet = false;
});
String errorMessage = "";
if (e is DioException && e.response != null) {
errorMessage = e.response?.data['message'] ?? e.toString();
} else {
errorMessage = e.toString();
}
SnackBar snackBar = SnackBar(content: Text(errorMessage));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
callback: (data) async {
setState(() {
wallet = data;
_isCreatingWallet = false;
});
log(data.toString());
},
);
} catch (e) {
setState(() {
_isCreatingWallet = false;
});
}
}
Future<void> _importWallet() async {
if (_isImportingWallet || !_isApiKeyPresent) {
if (!_isApiKeyPresent) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter an API key first')),
);
}
return;
}
setState(() {
_isImportingWallet = true;
});
try {
if (_importMethod == ImportMethod.privateKey) {
// Import using private key
final privateKey = _privateKeyController.text.trim();
if (privateKey.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter a private key')),
);
}
setState(() {
_isImportingWallet = false;
});
return;
}
if (!KalpDLTWallet.isValidPrivateKey(privateKey)) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Invalid private key format')),
);
}
setState(() {
_isImportingWallet = false;
});
return;
}
await kalpDlt.importWalletWithPrivateKey(
channelName: _nglChannleName,
privateKey: privateKey,
errorCallback: (dynamic e) {
setState(() {
_isImportingWallet = false;
});
String errorMessage = "";
if (e is DioException && e.response != null) {
errorMessage = e.response?.data['message'] ?? e.toString();
} else {
errorMessage = e.toString();
}
SnackBar snackBar = SnackBar(content: Text(errorMessage));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
callback: (data) async {
setState(() {
wallet = data;
_isImportingWallet = false;
});
log(data.toString());
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content:
Text('Wallet imported successfully with private key!')),
);
}
},
);
} else {
// Import using seed words (existing functionality)
final List<String> seedWords;
if (_useCustomSeeds && _customSeedController.text.isNotEmpty) {
seedWords = _customSeedController.text.trim().split(' ');
} else {
seedWords = KalpDLTWallet.lastGeneratedSeeds?.split(' ') ?? [];
}
if (seedWords.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'No seed words available. Please generate or enter seeds.')),
);
}
setState(() {
_isImportingWallet = false;
});
return;
}
await kalpDlt.createWalletWithSeedWords(
importWallet: true,
channelName: _nglChannleName,
seedWords: seedWords,
errorCallback: (dynamic e) {
setState(() {
_isImportingWallet = false;
});
String errorMessage = "";
if (e is DioException && e.response != null) {
errorMessage = e.response?.data['isregistered'] ?? false
? 'Wallet already registered'
: 'Wallet not registered';
} else {
errorMessage = e.toString();
}
SnackBar snackBar = SnackBar(content: Text(errorMessage));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
callback: (data) async {
setState(() {
wallet = data;
_isImportingWallet = false;
});
log(data.toString());
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Wallet imported successfully!')),
);
}
},
);
}
} catch (e) {
setState(() {
_isImportingWallet = false;
});
}
}
Future<void> read() async {
if (_isReading || !_isApiKeyPresent) {
if (!_isApiKeyPresent) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter an API key first')),
);
}
return;
}
setState(() {
_isReading = true;
});
try {
final data = await kalpDlt.read(
proposal: Proposal.empty().copyWith(
walletAddress: wallet.enrollmentId,
publicCertificate: wallet.publicCertificate,
network: _gatewayChannelName,
contractAddress: 'koot',
functionName: 'GetBalance',
functionParams: ['walletid355'],
));
setState(() {
_readResult = data.toString();
});
} catch (e) {
if (mounted) {
String errorMessage = "";
if (e is DioException && e.response != null) {
errorMessage = e.response?.data['message'].toString() ?? e.toString();
} else {
errorMessage = e.toString();
}
SnackBar snackBar = SnackBar(content: Text(errorMessage));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
} finally {
if (mounted) {
setState(() {
_isReading = false;
});
}
}
}
Future<void> write() async {
if (_isWriting || !_isApiKeyPresent) {
if (!_isApiKeyPresent) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter an API key first')),
);
}
return;
}
setState(() {
_isWriting = true;
});
try {
final data = await kalpDlt.write(
proposal: Proposal.empty().copyWith(
walletAddress: wallet.enrollmentId,
publicCertificate: wallet.publicCertificate,
network: _gatewayChannelName,
contractAddress: 'koot',
functionName: 'GetBalance',
functionParams: ['walletid355'],
));
setState(() {
_writeResult = data.toString();
});
} catch (e) {
if (mounted) {
String errorMessage = "";
if (e is DioException && e.response != null) {
errorMessage = e.response?.data['message'].toString() ?? e.toString();
} else {
errorMessage = e.toString();
}
SnackBar snackBar = SnackBar(content: Text(errorMessage));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
} finally {
if (mounted) {
setState(() {
_isWriting = false;
});
}
}
}
Future<void> getGasFees() async {
if (_isLoadingGasFees || !_isApiKeyPresent) {
if (!_isApiKeyPresent) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please enter an API key first')),
);
}
return;
}
setState(() {
_isLoadingGasFees = true;
});
try {
final data = await kalpDlt.gasFees(
proposal: Proposal.empty().copyWith(
walletAddress: wallet.enrollmentId,
publicCertificate: wallet.publicCertificate,
network: _gatewayChannelName,
contractAddress: 'klp-fbeadf7d20-cc',
functionName: 'GetGasFees',
functionParams: [],
));
setState(() {
_gasFeesResult = data.toString();
});
} catch (e) {
if (mounted) {
String errorMessage = "";
if (e is DioException && e.response != null) {
errorMessage = e.response?.data['message'].toString() ?? e.toString();
} else {
errorMessage = e.toString();
}
SnackBar snackBar = SnackBar(content: Text(errorMessage));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
} finally {
if (mounted) {
setState(() {
_isLoadingGasFees = false;
});
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
// API Key input field
TextField(
controller: _apiKeyController,
decoration: const InputDecoration(
labelText: 'API Key',
border: OutlineInputBorder(),
),
onChanged: (value) {
setState(() {
_updateKalpDLT();
});
},
),
const SizedBox(height: 20),
// Generate seed words section
ElevatedButton(
onPressed: _isGeneratingSeeds ? null : _generateSeedWords,
child: _isGeneratingSeeds
? const Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
SizedBox(width: 10),
Text('Generating...'),
],
)
: const Text('Generate Seed Words'),
),
if (_seedWords != null) ...[
const SizedBox(height: 10),
const Text('Generated Seed Words:'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
_seedWords!,
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
],
// Display wallet information when available
if (wallet != KalpWallet.empty()) ...[
const SizedBox(height: 20),
const Divider(),
const SizedBox(height: 10),
const Text('Wallet Information',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildWalletInfoRow(
'Enrollment ID', wallet.enrollmentId),
const Divider(),
const Text('Public Certificate:'),
Container(
height: 100,
margin: const EdgeInsets.only(top: 5),
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(4),
),
child: SingleChildScrollView(
child: Text(
wallet.publicCertificate.length > 100
? '${wallet.publicCertificate.substring(0, 100)}...'
: wallet.publicCertificate,
style: const TextStyle(fontSize: 12),
),
),
),
],
),
),
),
],
const SizedBox(height: 20),
const Divider(),
// Import wallet section with seed options
const SizedBox(height: 10),
const Text('Import Wallet',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
// Radio buttons for import method
Column(
children: [
RadioListTile<ImportMethod>(
title: const Text('Import with seed words'),
value: ImportMethod.seedWords,
groupValue: _importMethod,
onChanged: (ImportMethod? value) {
setState(() {
_importMethod = value!;
});
},
),
RadioListTile<ImportMethod>(
title: const Text('Import with private key'),
value: ImportMethod.privateKey,
groupValue: _importMethod,
onChanged: (ImportMethod? value) {
setState(() {
_importMethod = value!;
if (value == ImportMethod.privateKey) {
_useCustomSeeds =
false; // Disable custom seeds when using private key
}
});
},
),
],
),
if (_importMethod == ImportMethod.seedWords) ...[
// Toggle for seed source
Row(
children: [
Switch(
value: _useCustomSeeds,
onChanged: (value) {
setState(() {
_useCustomSeeds = value;
});
},
),
Text(_useCustomSeeds
? 'Using custom seeds'
: 'Using generated seeds'),
],
),
// Custom seed input field (visible only when toggle is on)
if (_useCustomSeeds) ...[
const SizedBox(height: 10),
TextField(
controller: _customSeedController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Enter seed words',
hintText: 'Separate words with spaces',
),
maxLines: 3,
),
],
],
// Private key input field (visible only when private key toggle is on)
if (_importMethod == ImportMethod.privateKey) ...[
const SizedBox(height: 10),
TextField(
controller: _privateKeyController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Enter private key',
hintText: 'Enter your private key (hex or PEM format)',
),
maxLines: 3,
),
],
const SizedBox(height: 10),
ElevatedButton(
onPressed: _isImportingWallet ? null : _importWallet,
child: _isImportingWallet
? const Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
SizedBox(width: 10),
Text('Importing...'),
],
)
: const Text('Import Wallet'),
),
const SizedBox(height: 20),
const Divider(),
// Other wallet operations
const SizedBox(height: 10),
const Text('Wallet Operations',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
ElevatedButton(
onPressed: _isCreatingWallet ? null : _createWallet,
child: _isCreatingWallet
? const Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
SizedBox(width: 10),
Text('Creating...'),
],
)
: const Text('Create New Wallet'),
),
ElevatedButton(
onPressed: _isReading ? null : read,
child: _isReading
? const Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
SizedBox(width: 10),
Text('Reading...'),
],
)
: const Text('Read'),
),
ElevatedButton(
onPressed: _isWriting ? null : write,
child: _isWriting
? const Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
SizedBox(width: 10),
Text('Writing...'),
],
)
: const Text('Write'),
),
ElevatedButton(
onPressed: _isLoadingGasFees ? null : getGasFees,
child: _isLoadingGasFees
? const Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
),
),
SizedBox(width: 10),
Text('Loading Gas Fees...'),
],
)
: const Text('Gas Fees'),
),
// Display results
if (_readResult != null) ...[
const SizedBox(height: 20),
const Text('Read Result:',
style:
TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
Text(_readResult!),
],
if (_writeResult != null) ...[
const SizedBox(height: 20),
const Text('Write Result:',
style:
TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
Text(_writeResult!),
],
if (_gasFeesResult != null) ...[
const SizedBox(height: 20),
const Text('Gas Fees Result:',
style:
TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
Text(_gasFeesResult!),
],
],
),
),
),
);
}
// Helper method to build wallet information rows
Widget _buildWalletInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 120,
child: Text(
label,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Expanded(
child: GestureDetector(
onTap: () async {
await Clipboard.setData(
ClipboardData(text: value),
);
},
child: Text(
value,
style: const TextStyle(
fontFamily: 'monospace',
),
),
),
),
],
),
);
}
}