zetrix_connect_wallet_sdk 1.0.1
zetrix_connect_wallet_sdk: ^1.0.1 copied to clipboard
A Flutter package for integrating Zetrix blockchain wallet connectivity and operations.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:zetrix_connect_wallet_sdk/zetrix_connect_wallet_sdk.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Zetrix SDK Dapp Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late ZetrixWalletConnect _walletConnect;
String _sessionId = 'Not connected';
String _deviceInfo = 'Unknown';
String _address = 'Unknown';
String _lastResult = 'No operation performed yet';
bool _useCustomQrUi = false; // Toggle for custom QR UI
@override
void initState() {
super.initState();
_initializeWallet();
_loadDeviceInfo();
_loadSession();
}
/// Initialize wallet based on custom QR toggle
void _initializeWallet() {
_walletConnect = ZetrixWalletConnect(
testnet: false,
qrcode: true,
appType: 'zetrix',
isCustomQrUi: _useCustomQrUi,
qrDataCallback: _useCustomQrUi ? _showCustomQrDialog : null,
);
}
/// Show custom QR code dialog
void _showCustomQrDialog(String qrContent) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => _CustomQrDialog(
qrContent: qrContent,
onClose: () => Navigator.of(context).pop(),
),
);
}
Future<void> _loadDeviceInfo() async {
try {
final info = await DeviceUtils.getDeviceInfo();
final appInfo = await DeviceUtils.getAppInfo();
setState(() {
_deviceInfo = '${info['model']} (${info['platform']}) - App: ${appInfo['appName']} (${appInfo['packageName']})';
});
} catch (e) {
setState(() {
_deviceInfo = 'Error: $e';
});
}
}
Future<void> _loadSession() async {
final sessionId = await StorageUtils.getSessionId();
final address = await StorageUtils.getAddress();
setState(() {
_sessionId = sessionId ?? 'Not connected';
_address = address ?? 'Unknown';
});
}
Future<void> _connectWallet() async {
try {
final connectResult = await _walletConnect.connect();
final storedSessionId = await StorageUtils.getSessionId();
final storedAddress = await StorageUtils.getAddress();
setState(() {
if (storedSessionId != null && storedAddress != null) {
_sessionId = storedSessionId;
_address = storedAddress;
} else {
_sessionId = 'Connected (ready for auth)';
}
});
} catch (e) {
setState(() {
_sessionId = 'Connection failed: $e';
});
}
}
Future<void> _authWallet() async {
try {
final authResult = await _walletConnect.auth(context);
if (authResult['code'] == 0) {
// Close custom QR dialog if it's open
if (_useCustomQrUi && Navigator.canPop(context)) {
Navigator.of(context).pop();
}
setState(() {
_sessionId = authResult['data']['sessionId'] ?? 'Authenticated (no session ID)';
_address = authResult['data']['address'] ?? 'No address returned';
});
} else {
setState(() {
_sessionId = 'Auth failed: ${authResult['message']}';
});
}
} catch (e) {
setState(() {
_sessionId = 'Auth failed: $e';
});
}
}
Future<void> _authAndSignMessage() async {
try {
final result = await _walletConnect.authAndSignMessage(
context,
{'message': 'Auth and sign in one step!'},
);
if (result['code'] == 0) {
// Close custom QR dialog if it's open
if (_useCustomQrUi && Navigator.canPop(context)) {
Navigator.of(context).pop();
}
setState(() {
_sessionId = result['data']['sessionId'] ?? 'Authenticated';
_address = result['data']['address'] ?? 'No address returned';
_lastResult = 'AuthAndSignMessage Success:\nSessionId: ${result['data']['sessionId']}\nAddress: ${result['data']['address']}\nPublicKey: ${result['data']['publicKey']}\nSignData: ${result['data']['signData']}';
});
} else {
setState(() {
_lastResult = 'AuthAndSignMessage Failed: ${result['message']}';
});
}
} catch (e) {
setState(() {
_lastResult = 'AuthAndSignMessage Error: $e';
});
}
}
Future<void> _disconnectWallet() async {
_walletConnect.closeConnect();
_walletConnect.disconnect();
setState(() {
_sessionId = 'Not connected';
_address = 'Unknown';
_lastResult = 'Disconnected';
});
}
Future<void> _signMessage() async {
try {
final result = await _walletConnect.signMessage({
'message': 'Hello from Zetrix SDK Flutter!',
});
if (result['code'] == 0) {
setState(() {
_lastResult = 'SignMessage Success:\nAddress: ${result['data']['address']}\nPublicKey: ${result['data']['publicKey']}\nSignData: ${result['data']['signData']}';
});
} else {
setState(() {
_lastResult = 'SignMessage Failed: ${result['message']}';
});
}
} catch (e) {
setState(() {
_lastResult = 'SignMessage Error: $e';
});
}
}
Future<void> _signBlob() async {
try {
final result = await _walletConnect.signBlob({
'message': 'AAAAAAbcdef',
});
if (result['code'] == 0) {
setState(() {
_lastResult = 'SignBlob Success:\nAddress: ${result['data']['address']}\nPublicKey: ${result['data']['publicKey']}\nSignData: ${result['data']['signData']}';
});
} else {
setState(() {
_lastResult = 'SignBlob Failed: ${result['message']}';
});
}
} catch (e) {
setState(() {
_lastResult = 'SignBlob Error: $e';
});
}
}
Future<void> _getNonce() async {
try {
if (_address == 'Unknown' || _address.isEmpty) {
setState(() {
_lastResult = 'GetNonce Failed: Please authenticate first';
});
return;
}
final result = await _walletConnect.getNonce({
'address': _address,
'chainId': '1',
});
if (result['code'] == 0) {
setState(() {
_lastResult = 'GetNonce Success:\nNonce: ${result['data']['nonce']}';
});
} else {
setState(() {
_lastResult = 'GetNonce Failed: ${result['message']}';
});
}
} catch (e) {
setState(() {
_lastResult = 'GetNonce Error: $e';
});
}
}
Future<void> _sendTransaction() async {
try {
if (_address == 'Unknown' || _address.isEmpty) {
setState(() {
_lastResult = 'SendTransaction Failed: Please authenticate first';
});
return;
}
// First get nonce
final nonceResult = await _walletConnect.getNonce({
'address': _address,
'chainId': '1',
});
if (nonceResult['code'] != 0) {
setState(() {
_lastResult = 'SendTransaction Failed: Could not get nonce';
});
return;
}
final nonce = nonceResult['data']['nonce'];
final result = await _walletConnect.sendTransaction({
'from': _address,
'to': 'ZTX3QkbTjJsc7xDbwRtuHn826cAYF79uKR3rt', // Example recipient
'amount': '1', // 1 ZTX (in smallest unit)
'gasFee': '0.0001',
'nonce': nonce,
'data': '',
'chainId': '1',
});
if (result['code'] == 0) {
setState(() {
_lastResult = 'SendTransaction Success:\nHash: ${result['data']['hash']}';
});
} else {
setState(() {
_lastResult = 'SendTransaction Failed: ${result['message']}';
});
}
} catch (e) {
setState(() {
_lastResult = 'SendTransaction Error: $e';
});
}
}
Future<void> _verifyVC() async {
try {
if (_address == 'Unknown' || _address.isEmpty) {
setState(() {
_lastResult = 'VerifyVC Failed: Please authenticate first';
});
return;
}
final result = await _walletConnect.verifyVC({
'templateId': 'example-template-id-123',
});
if (result['code'] == 0) {
setState(() {
_lastResult = 'VerifyVC Success:\nStatus: ${result['data']['status']}\nDetails: ${result['data']['details']}';
});
} else {
setState(() {
_lastResult = 'VerifyVC Failed: ${result['message']}';
});
}
} catch (e) {
setState(() {
_lastResult = 'VerifyVC Error: $e';
});
}
}
Future<void> _getVP() async {
try {
if (_address == 'Unknown' || _address.isEmpty) {
setState(() {
_lastResult = 'GetVP Failed: Please authenticate first';
});
return;
}
final result = await _walletConnect.getVP({
'templateId': 'example-template-id-456',
'attributes': ['name', 'email', 'phone'],
});
if (result['code'] == 0) {
setState(() {
_lastResult = 'GetVP Success:\nUUID: ${result['data']['uuid']}';
});
} else {
setState(() {
_lastResult = 'GetVP Failed: ${result['message']}';
});
}
} catch (e) {
setState(() {
_lastResult = 'GetVP Error: $e';
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Zetrix SDK Example'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Custom QR UI Toggle
Card(
color: Colors.deepPurple.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
Icons.qr_code_2,
color: Colors.white,
size: 24,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
'Custom QR Code UI',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.deepPurple,
),
),
SizedBox(height: 4),
Text(
'Toggle to use custom QR code display',
style: TextStyle(fontSize: 12),
),
],
),
),
Switch(
value: _useCustomQrUi,
activeColor: Colors.deepPurple,
onChanged: (value) {
setState(() {
_useCustomQrUi = value;
// Reinitialize wallet with new settings
_initializeWallet();
});
},
),
],
),
),
),
const SizedBox(height: 24),
Text('Device: $_deviceInfo'),
const SizedBox(height: 16),
Text('Session: $_sessionId'),
const SizedBox(height: 16),
Text('Address: $_address'),
const SizedBox(height: 32),
// Connection Section
const Text(
'Connection:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _connectWallet,
child: const Text('Connect'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: _authWallet,
child: const Text('Auth'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: _disconnectWallet,
child: const Text('Disconnect'),
),
),
],
),
const SizedBox(height: 8),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _authAndSignMessage,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
),
child: const Text('Auth & Sign Message'),
),
),
const SizedBox(height: 24),
// Signing Section
const Text(
'Signing Operations:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _signMessage,
child: const Text('Sign Message'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: _signBlob,
child: const Text('Sign Blob'),
),
),
],
),
const SizedBox(height: 24),
// Transaction Section
const Text(
'Transaction Operations:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _getNonce,
child: const Text('Get Nonce'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: _sendTransaction,
child: const Text('Send Transaction'),
),
),
],
),
const SizedBox(height: 24),
// Verifiable Credentials Section
const Text(
'Verifiable Credentials:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _verifyVC,
child: const Text('Verify VC'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: _getVP,
child: const Text('Get VP'),
),
),
],
),
const SizedBox(height: 32),
// Last Result Section
const Text(
'Last Result:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8),
),
child: Text(
_lastResult,
style: const TextStyle(fontSize: 12, fontFamily: 'monospace'),
),
),
const SizedBox(height: 32),
const Text(
'SDK Features:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text('• Wallet Connection via WebSocket'),
const Text('• Secure Storage'),
const Text('• Device Information'),
const Text('• QR Code Generation (Built-in & Custom)'),
const Text('• App Linking'),
const Text('• Cryptographic Utilities'),
],
),
),
);
}
}
/// Custom QR Code Dialog Widget
///
/// This widget demonstrates a custom-styled QR code dialog
/// that you can customize to match your app's branding.
class _CustomQrDialog extends StatelessWidget {
final String qrContent;
final VoidCallback onClose;
const _CustomQrDialog({
required this.qrContent,
required this.onClose,
});
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.deepPurple.shade50, Colors.white],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
borderRadius: BorderRadius.circular(20),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Custom branding icon
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(50),
),
child: const Icon(
Icons.account_balance_wallet,
size: 32,
color: Colors.white,
),
),
const SizedBox(height: 16),
// Title
const Text(
'Connect Your Wallet',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.deepPurple,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
// Instructions
const Text(
'Scan this QR code with your Zetrix Wallet app to connect',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
// QR Code
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 2,
blurRadius: 5,
),
],
),
child: QrImageView(
data: qrContent,
version: QrVersions.auto,
size: 220.0,
backgroundColor: Colors.white,
),
),
const SizedBox(height: 16),
// Waiting text
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.deepPurple.withOpacity(0.5),
),
),
const SizedBox(width: 8),
Text(
'Waiting for wallet to scan...',
style: TextStyle(
fontSize: 12,
color: Colors.grey.withOpacity(0.7),
),
),
],
),
const SizedBox(height: 20),
// Cancel button
SizedBox(
width: double.infinity,
child: OutlinedButton(
onPressed: onClose,
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.deepPurple),
padding: const EdgeInsets.symmetric(vertical: 12),
),
child: const Text(
'Cancel',
style: TextStyle(color: Colors.deepPurple),
),
),
),
const SizedBox(height: 12),
// QR Data format info
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(8),
),
child: Text(
'QR Data Format: {rms}&{sessionId}&{type}',
style: TextStyle(
fontSize: 10,
color: Colors.grey.shade600,
fontFamily: 'monospace',
),
textAlign: TextAlign.center,
),
),
],
),
),
);
}
}