Flutter Solana钱包管理插件solana_wallet_adapter的使用
Flutter Solana钱包管理插件 solana_wallet_adapter
的使用
solana_wallet_adapter
是一个实现了 Solana 移动钱包适配器协议的 Dart 库。该库允许 dApps 与 Android 和 iOS 上的钱包应用程序(如 Solflare)进行交互。
非特权方法
非特权方法不需要当前会话处于授权状态即可调用:
authorize
deauthorize
reauthorize
getCapabilities
特权方法
特权方法需要当前会话处于授权状态才能调用:
signTransactions
signAndSendTransactions
signMessages
设置
确保你的钱包应用(例如 Phantom)和 SolanaWalletAdapter
连接到相同的网络。请注意,钱包应用可能不支持本地主机。
示例:授权
以下是一个简单的示例,展示了如何使用 solana_wallet_adapter
来授权应用:
import 'package:flutter/material.dart';
import 'package:solana_wallet_adapter/solana_wallet_adapter.dart';
void main() {
runApp(const MaterialApp(
home: Scaffold(
body: Center(
child: AuthorizeButton(),
),
),
));
}
// 创建 [SolanaWalletAdapter] 实例。
final adapter = SolanaWalletAdapter(
const AppIdentity(),
// 注意:将钱包应用连接到同一个网络。
cluster: Cluster.devnet,
);
class AuthorizeButton extends StatefulWidget {
const AuthorizeButton({super.key});
[@override](/user/override)
State<AuthorizeButton> createState() => _AuthorizeButtonState();
}
class _AuthorizeButtonState extends State<AuthorizeButton> {
Object? _output;
[@override](/user/override)
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () {
// 授权应用与钱包交互。
adapter.authorize()
.then((result) => setState(() => _output = result.toJson()))
.catchError((error) => setState(() => _output = error));
},
child: const Text('Authorize'),
),
if (_output != null)
Text(_output.toString()),
],
);
}
}
完整示例 Demo
下面是一个更完整的示例,展示了如何连接、断开连接、签名交易以及发送交易等操作:
/// 导入必要的包
import 'package:flutter/material.dart';
import 'package:solana_wallet_adapter/solana_wallet_adapter.dart';
import 'package:solana_web3/programs.dart';
import 'package:solana_web3/solana_web3.dart';
/// 主函数
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MaterialApp(
home: Scaffold(
body: ExampleApp(),
),
));
}
/// 转账数据结构
class TransferData {
const TransferData({
required this.transaction,
required this.receiver,
required this.lamports,
});
final Transaction transaction;
final Keypair receiver;
final BigInt lamports;
}
/// 示例应用
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
[@override](/user/override)
State<ExampleApp> createState() => _ExampleAppState();
}
/// 示例应用状态
class _ExampleAppState extends State<ExampleApp> {
late final Future<void> _future;
String? _status;
static final Cluster cluster = Cluster.devnet;
final SolanaWalletAdapter adapter = SolanaWalletAdapter(
AppIdentity(),
cluster: cluster,
hostAuthority: null,
);
[@override](/user/override)
void initState() {
super.initState();
_future = SolanaWalletAdapter.initialize();
}
Future<void> _connect() async {
if (!adapter.isAuthorized) {
await adapter.authorize(walletUriBase: adapter.store.apps[1].walletUriBase);
setState(() {});
}
}
Future<void> _disconnect() async {
if (adapter.isAuthorized) {
await adapter.deauthorize();
setState(() {});
}
}
Future<void> _airdrop(final Connection connection, final Pubkey wallet) async {
if (cluster != Cluster.mainnet) {
setState(() => _status = "Requesting airdrop...");
await connection.requestAndConfirmAirdrop(wallet, solToLamports(2).toInt());
}
}
Future<List<TransferData>> _createTransfers(final Connection connection, {required int count}) async {
final Pubkey? wallet = Pubkey.tryFromBase64(adapter.connectedAccount?.address);
if (wallet == null) {
throw 'Wallet not connected';
}
final BigInt lamports = solToLamports(0.001);
if ((await connection.getBalance(wallet)) < (1000000 + lamports.toInt())) {
await _airdrop(connection, wallet);
}
final latestBlockhash = await connection.getLatestBlockhash();
final List<TransferData> txs = [];
for (int i = 0; i < count; ++i) {
final Keypair receiver = Keypair.generateSync();
final Transaction transaction = Transaction.v0(
payer: wallet,
recentBlockhash: latestBlockhash.blockhash,
instructions: [
SystemProgram.transfer(
fromPubkey: wallet,
toPubkey: receiver.pubkey,
lamports: lamports,
)
]
);
txs.add(TransferData(transaction: transaction, receiver: receiver, lamports: lamports));
}
return txs;
}
Future<void> _confirmTransfers(final Connection connection, {required List<String?> signatures, required List<TransferData> transfers}) async {
await Future.wait(signatures.map((sig) => connection.confirmTransaction(base58To64Decode(sig!))), eagerError: true);
final List<int> receiverBalances = await Future.wait(transfers.map((transfer) => connection.getBalance(transfer.receiver.pubkey)), eagerError: true);
final List<String> results = [];
for (int i = 0; i < receiverBalances.length; ++i) {
final TransferData transfer = transfers[i];
final Pubkey pubkey = transfer.receiver.pubkey;
final BigInt balance = receiverBalances[i].toBigInt();
if (balance != transfer.lamports) throw Exception('Post transaction balance mismatch.');
results.add("Transfer: Address $pubkey received $balance SOL");
}
setState(() => _status = "Success!\n\nSignatures: $signatures\n\n${results.join('\n')}");
}
void _signTransactions(final int count) async {
try {
final Connection connection = Connection(cluster);
final List<TransferData> transfers = await _createTransfers(connection, count: count);
final SignTransactionsResult result = await adapter.signTransactions(
transfers.map((transfer) => adapter.encodeTransaction(transfer.transaction)).toList(),
);
final List<String?> signatures = await connection.sendSignedTransactions(result.signedPayloads, eagerError: true);
await _confirmTransfers(connection, signatures: signatures.map((e) => base58To64Encode(e!)).toList(), transfers: transfers);
} catch (error, stack) {
print('Sign Transactions Error: $error');
print('Sign Transactions Stack: $stack');
setState(() => _status = error.toString());
}
}
Widget _builder(final BuildContext context, final AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const CircularProgressIndicator();
}
return ListView(
shrinkWrap: true,
padding: const EdgeInsets.all(24.0),
children: [
adapter.isAuthorized
? Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('${adapter.connectedAccount?.toBase58()}', textAlign: TextAlign.center),
ElevatedButton(onPressed: _disconnect, style: ElevatedButton.styleFrom(backgroundColor: Colors.red), child: const Text('Disconnect')),
],
)
: ElevatedButton(onPressed: _connect, child: const Text('Connect')),
const Divider(),
Wrap(
spacing: 24.0,
runSpacing: 8.0,
children: [
ElevatedButton(onPressed: adapter.isAuthorized ? () => _signTransactions(1) : null, child: const Text('Sign Transactions (1)')),
ElevatedButton(onPressed: adapter.isAuthorized ? () => _signTransactions(3) : null, child: const Text('Sign Transactions (3)')),
],
),
Text(_status ?? ''),
],
);
}
[@override](/user/override)
Widget build(final BuildContext context) {
return Center(child: FutureBuilder(future: _future, builder: _builder));
}
}
更多关于Flutter Solana钱包管理插件solana_wallet_adapter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter Solana钱包管理插件solana_wallet_adapter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用solana_wallet_adapter
插件的示例代码。这个插件允许你管理Solana钱包,包括连接、签名交易等功能。
首先,确保你已经在pubspec.yaml
文件中添加了solana_wallet_adapter
依赖项:
dependencies:
flutter:
sdk: flutter
solana_wallet_adapter: ^最新版本号 # 替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
接下来,我们创建一个简单的Flutter应用来演示如何使用solana_wallet_adapter
。
主应用文件 (main.dart)
import 'package:flutter/material.dart';
import 'package:solana_wallet_adapter/solana_wallet_adapter.dart';
import 'package:solana_wallet_adapter_wallets/solana_wallet_adapter_wallets.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Solana Wallet Adapter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: WalletManagerPage(),
);
}
}
class WalletManagerPage extends StatefulWidget {
@override
_WalletManagerPageState createState() => _WalletManagerPageState();
}
class _WalletManagerPageState extends State<WalletManagerPage> {
late WalletAdapter walletAdapter;
@override
void initState() {
super.initState();
// 初始化钱包适配器
walletAdapter = WalletAdapter(
wallets: [
// 添加你希望支持的钱包类型
PhantomWallet(),
SolletWallet(),
// 添加更多钱包类型...
],
autoConnect: true, // 自动连接最后一个使用的钱包
);
// 监听钱包状态变化
walletAdapter.onReady.listen((_) {
print('Wallet is ready!');
// 这里可以执行一些初始化操作,比如获取钱包余额等
});
walletAdapter.onDisconnected.listen((_) {
print('Wallet is disconnected!');
});
// 加载钱包
walletAdapter.load();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Solana Wallet Manager'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (walletAdapter.connected)
Text(
'Connected Wallet: ${walletAdapter.publicKey?.toBase58()}',
style: TextStyle(fontSize: 20),
)
else
Text(
'No Wallet Connected',
style: TextStyle(fontSize: 20, color: Colors.red),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
if (!walletAdapter.connected) {
await walletAdapter.connect();
} else {
await walletAdapter.disconnect();
}
},
child: Text(walletAdapter.connected ? 'Disconnect' : 'Connect'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
if (walletAdapter.connected) {
// 这里可以执行一些需要签名的交易操作
// 例如,发送SOL,或者调用一个智能合约
// 注意:这只是一个示例,实际交易需要更多的代码和安全性检查
print('Executing a transaction...');
// await walletAdapter.signTransaction(...);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Please connect a wallet first!')),
);
}
},
child: Text('Execute Transaction'),
),
],
),
),
);
}
}
注意事项
-
安全性:在实际应用中,处理钱包和交易时需要特别注意安全性。确保你的应用通过安全的通道与钱包交互,并且用户充分理解他们正在执行的操作。
-
依赖管理:确保你的项目依赖是最新的,因为
solana_wallet_adapter
和相关插件可能会更新。 -
错误处理:示例代码中没有包含详细的错误处理逻辑。在实际应用中,你应该添加适当的错误处理来应对连接失败、交易失败等情况。
-
更多功能:
solana_wallet_adapter
插件提供了更多功能,比如监听账户余额变化、监听交易确认等。你可以查阅官方文档来了解这些功能。
这个示例代码展示了如何使用solana_wallet_adapter
插件来管理Solana钱包的基本操作。你可以根据需要进行扩展和修改。