ton_wallet_v4 1.0.0
ton_wallet_v4: ^1.0.0 copied to clipboard
A Flutter plugin for generating TON blockchain wallets, mnemonics, and fetching wallet assets.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:ton_wallet_v4/ton_wallet_bridge.dart';
void main() {
runApp(const TonV4WalletExample());
}
class TonV4WalletExample extends StatelessWidget {
const TonV4WalletExample({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: TonExamplePage());
}
}
class TonExamplePage extends StatefulWidget {
const TonExamplePage({super.key});
@override
State<TonExamplePage> createState() => _TonExamplePageState();
}
class _TonExamplePageState extends State<TonExamplePage> {
final TonWallet _bridge = TonWallet();
final TextEditingController _mnemonicController = TextEditingController();
final TextEditingController _addressController = TextEditingController(text: 'UQDl1TmBo5PIgq0nW-cz2raZuleMLm99sO-uvGcr6S1B2rOM');
String _status = 'Generate mnemonic or enter your own mnemonic.';
String _walletJson = '';
Map<String, dynamic> _assets = {};
bool _loading = false;
@override
void dispose() {
_mnemonicController.dispose();
_addressController.dispose();
super.dispose();
}
List<String> _mnemonicWords() {
return _mnemonicController.text
.trim()
.split(RegExp(r'\s+'))
.where((e) => e.isNotEmpty)
.toList();
}
Future<void> _generateMnemonic() async {
setState(() => _loading = true);
try {
final words = await _bridge.generateMnemonic();
setState(() {
_mnemonicController.text = words.join(' ');
_status = 'Generated ${words.length}-word mnemonic.';
});
} on PlatformException catch (e) {
setState(() => _status = e.message ?? e.code);
} finally {
if (mounted) {
setState(() => _loading = false);
}
}
}
Future<void> _generateWallet() async {
final mnemonic = _mnemonicWords();
if (mnemonic.isEmpty) {
setState(() => _status = 'Mnemonic is required.');
return;
}
setState(() => _loading = true);
try {
final wallet = await _bridge.generateV4Wallet(mnemonic: mnemonic);
setState(() {
_walletJson = const JsonEncoder.withIndent(' ').convert(wallet);
// _addressController.text = wallet['address'] ?? '';
_status = 'V4 wallet generated.';
});
} on PlatformException catch (e) {
setState(() => _status = e.message ?? e.code);
} finally {
if (mounted) {
setState(() => _loading = false);
}
}
}
Future<void> _fetchAssets() async {
final address = _addressController.text.trim();
if (address.isEmpty) {
setState(() => _status = 'Address is required.');
return;
}
setState(() => _loading = true);
try {
final assets = await _bridge.fetchAssets(address: address);
setState(() {
_assets = assets;
_status = 'Assets fetched successfully.';
});
} on PlatformException catch (e) {
setState(() => _status = 'Error: ${e.message ?? e.code}');
} finally {
if (mounted) {
setState(() => _loading = false);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('TON Flutter Example')),
body: Padding(
padding: const EdgeInsets.all(16),
child: ListView(
children: [
// Mnemonic Section
const Text(
'Mnemonic',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 8),
TextField(
controller: _mnemonicController,
minLines: 3,
maxLines: 5,
decoration: const InputDecoration(
labelText: 'Mnemonic (space separated)',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
FilledButton(
onPressed: _loading ? null : _generateMnemonic,
child: const Text('Generate Mnemonic'),
),
FilledButton(
onPressed: _loading ? null : _generateWallet,
child: const Text('Generate V4 Wallet'),
),
],
),
const SizedBox(height: 16),
// Wallet Data Section
const Text(
'Wallet Data',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(4),
),
child: SelectableText(
_walletJson.isEmpty ? 'No wallet generated yet.' : _walletJson,
style: const TextStyle(fontSize: 12),
),
),
const SizedBox(height: 16),
// Assets Section
const Text(
'Assets',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 8),
TextField(
controller: _addressController,
decoration: const InputDecoration(
labelText: 'Wallet Address',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 8),
FilledButton(
onPressed: _loading ? null : _fetchAssets,
child: const Text('Fetch Assets'),
),
const SizedBox(height: 16),
// Assets Display
if (_assets.isNotEmpty)
_buildAssetsDisplay()
else
const Text('No assets loaded. Enter address and fetch assets.'),
const SizedBox(height: 16),
Text('Status: $_status'),
],
),
),
);
}
Widget _buildAssetsDisplay() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(4),
border: Border.all(color: Colors.blue.shade200),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'TON Balance',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue.shade700,
),
),
const SizedBox(height: 8),
Text(
'${_assets['tonBalance'] ?? '0'} TON',
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
),
const SizedBox(height: 4),
Text(
'Nanotons: ${_assets['tonBalanceNano'] ?? '0'}',
style: TextStyle(fontSize: 12, color: Colors.grey.shade600),
),
],
),
),
const SizedBox(height: 16),
const Text(
'Tokens',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
),
const SizedBox(height: 8),
_buildJettonsList(),
],
);
}
Widget _buildJettonsList() {
final jettons = _assets['jettons'] as List<dynamic>? ?? [];
if (jettons.isEmpty) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(4),
),
child: const Text('No tokens found.'),
);
}
// UQDl1TmBo5PIgq0nW-cz2raZuleMLm99sO-uvGcr6S1B2rOM
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: jettons.length,
itemBuilder: (context, index) {
final jettonData = jettons[index];
final jetton = jettonData is Map
? Map<String, dynamic>.from(jettonData as Map)
: <String, dynamic>{};
return Card(
margin: const EdgeInsets.only(bottom: 8),
child: ListTile(
title: Text(jetton['name'] ?? 'Unknown Token'),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 4),
Text(
'Symbol: ${jetton['symbol'] ?? '???'}',
style: const TextStyle(fontSize: 12),
),
Text(
'Balance: ${jetton['balance'] ?? '0'}',
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
if (jetton['jettonAddress'] != null)
Text(
'Address: ${jetton['jettonAddress']}',
style: const TextStyle(fontSize: 10, color: Colors.grey),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
);
},
);
}
}