Flutter Cardano区块链交互插件ledger_cardano_plus的使用
Flutter Cardano区块链交互插件ledger_cardano_plus的使用
概述
Ledger Nano设备是管理您的加密货币和NFT的理想硬件钱包。此Flutter插件通过ledger_flutter_plus
包为Cardano区块链提供获取账户和签名交易的功能。
开始使用
安装
在pubspec.yaml
文件中安装最新版本的插件:
ledger_cardano_plus: ^latest-version
ledger_flutter_plus: ^latest-version
对于与ledger_flutter_plus
包的集成,请参阅文档此处。
设置和使用
首先,获取CardanoLedger
实例并使用它来扫描和连接到设备。
final CardanoLedger cardanoLedgerConnector = CardanoLedger.ble(
onPermissionRequest: (status) async {
// 如果状态为不可用,则返回false
// 使用permission_handler包
Map<Permission, PermissionStatus> statuses = await [
Permission.location,
Permission.bluetoothScan,
Permission.bluetoothConnect,
Permission.bluetoothAdvertise,
].request();
return statuses.values.where((status) => status.isDenied).isEmpty;
},
);
// 对于USB连接
// final CardanoLedger cardanoLedgerConnector = CardanoLedger.usb();
final devicesStream = cardanoLedgerConnector.scanForDevices();
// 最好监听流并允许用户选择所需的Ledger设备
final firstLedgerDevice = await devicesStream.first;
final cardanoApp = cardanoLedgerConnector.connect(firstLedgerDevice);
// 获取接收地址
final receiveAddress = await cardanoApp.deriveReceiveAddress(
addressIndex: addressIndex,
network: CardanoNetwork.mainnet(),
);
要获取更深入的示例,包括设备选择对话框,请查看此存储库中的示例项目。
赞助商
我们的顶级赞助商如下所示!
|
贡献
贡献使开源社区成为学习、启发和创造的绝佳场所。任何贡献都将受到极大的赞赏。
如果您有任何改进建议,请在仓库上创建一个拉取请求。您也可以简单地打开一个带有标签enhancement
的issue。
- 分支项目
- 创建您的功能分支 (
git checkout -b feature/my-feature
) - 提交更改 (
git commit -m 'feat: my new feature'
) - 推送到分支 (
git push origin feature/my-feature
) - 打开拉取请求
运行集成测试
要运行ledger-cardano-plus
SDK的集成测试,请按照以下步骤操作:
-
设置环境: 确保您的机器上已安装Flutter。您可以从Flutter官方站点下载它。
-
克隆仓库: 如果您尚未克隆,从GitHub克隆
ledger-cardano-plus
仓库:git clone https://github.com/vespr-wallet/ledger-cardano-plus.git cd ledger-cardano-plus
-
导航到集成测试目录: 更改到包含集成测试的目录:
cd example/integration_test
-
运行测试: 使用以下Flutter命令执行所有集成测试:
cd example flutter test integration_test/*_tests.dart
若要运行特定的集成测试文件,请提供测试文件路径:
cd example flutter test integration_test/cardano_ledger_serial_version_tests.dart
若要运行测试文件中的特定测试用例,请使用
-n
标志后跟测试名称:cd example flutter test integration_test/cardano_ledger_serial_version_tests.dart -n "Should correctly get the serial number of the device"
确保您的开发环境能够与Ledger设备通信,并且在运行测试之前设备已连接并解锁。
许可证
ledger_cardano_plus
SDK在MIT许可证下发布。详情见LICENSE文件。
示例代码
以下是main.dart
文件的示例代码:
import 'dart:async';
import 'package:example/sample_utils/operations.dart';
import 'package:example/widgets/available_devices.dart';
import 'package:flutter/material.dart';
import 'package:ledger_cardano_plus/ledger_cardano_plus.dart';
import 'package:permission_handler/permission_handler.dart';
const _awaitingLedgerResponse = '[Awaiting Ledger Response...]';
void main() {
CardanoLedger.debugPrintEnabled = true;
runApp(const MainWidget());
}
class MainWidget extends StatelessWidget {
const MainWidget({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: SafeArea(
child: SizedBox(
width: double.infinity,
child: MyApp(),
),
),
),
);
}
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late final CardanoLedger cardanoLedgerConnector = CardanoLedger.ble(
onPermissionRequest: ({required bool unsupported}) async {
if (unsupported) {
return false;
}
Map<Permission, PermissionStatus> statuses = await [
Permission.location,
Permission.bluetoothScan,
Permission.bluetoothConnect,
Permission.bluetoothAdvertise,
].request();
return statuses.values.where((status) => status.isDenied).isEmpty;
},
);
bool connecting = false;
CardanoLedgerConnection? cardanoLedgerConnection;
String? error;
String? resultTitle;
String? resultData;
void _onOperationRequested({
required String operation,
required FutureOr<String> Function() invoker,
}) async {
try {
resultTitle = operation;
resultData = _awaitingLedgerResponse;
setState(() {});
resultData = await invoker();
} catch (e) {
resultData = 'Unhandled Error: ${e.toString()}';
}
setState(() {});
}
[@override](/user/override)
Widget build(BuildContext context) {
final cardanoLedgerConnection = this.cardanoLedgerConnection;
final error = this.error;
if (connecting) {
return const Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Connecting to Ledger Device...',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(height: 32),
CircularProgressIndicator(),
],
),
);
}
if (cardanoLedgerConnection == null || error != null) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: _onScanForLedgerDevicesPressed,
child: const Text('Scan for Ledger Devices'),
),
if (error != null)
Text(
'Error connecting to selected device\n$error',
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.redAccent,
fontWeight: FontWeight.bold,
),
)
],
),
);
}
final selectedDevice = cardanoLedgerConnection.device;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Connected to ${selectedDevice.name}\n${selectedDevice.id}',
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
color: Colors.blueAccent,
fontWeight: FontWeight.bold,
),
),
const Divider(),
const SizedBox(height: 8),
OutlinedButton(
onPressed: () => _onOperationRequested(
operation: "Disconnect Device",
invoker: () async {
final result = reset(cardanoLedgerConnection);
await cardanoLedgerConnection.disconnect();
setState(() {
this.cardanoLedgerConnection = null;
this.error = null;
connecting = false;
});
return result;
},
),
child: const Text('Disconnect Device'),
),
const SizedBox(height: 16),
Wrap(
spacing: 16,
runSpacing: 4,
alignment: WrapAlignment.center,
children: [
ElevatedButton(
onPressed: () => _onOperationRequested(
operation: "Fetch Serial Number",
invoker: () => fetchSerial(cardanoLedgerConnection),
),
child: const Text('Fetch Serial Number'),
),
ElevatedButton(
onPressed: () => _onOperationRequested(
operation: "Fetch App Version",
invoker: () => fetchVersion(cardanoLedgerConnection),
),
child: const Text('Fetch App Version'),
),
ElevatedButton(
onPressed: () => _onOperationRequested(
operation: "Fetch Cardano Wallet Public Key",
invoker: () => fetchPublicKey(cardanoLedgerConnection),
),
child: const Text('Fetch Public Key'),
),
ElevatedButton(
onPressed: () => _onOperationRequested(
operation: "Fetch Stake Address",
invoker: () => fetchStakeAddress(cardanoLedgerConnection),
),
child: const Text('Fetch Stake Address'),
),
ElevatedButton(
onPressed: () => _onOperationRequested(
operation: "Fetch Receive Addresses",
invoker: () => fetchReceiveAddresses(
cardanoLedgerConnection,
addressIndices: [0, 1, 2, 3],
),
),
child: const Text('Fetch Receive Addresses'),
),
ElevatedButton(
onPressed: () => _onOperationRequested(
operation: "Fetch Change Addresses",
invoker: () => fetchChangeAddresses(
cardanoLedgerConnection,
addressIndices: [0, 1, 2, 3],
),
),
child: const Text('Fetch Change Addresses'),
),
ElevatedButton(
onPressed: () => _onOperationRequested(
operation: "Sign Transaction",
invoker: () => signTransaction(cardanoLedgerConnection),
),
child: const Text('Sign Transaction'),
),
],
),
const SizedBox(height: 16),
Expanded(
child: Padding(
padding: const EdgeInsets.all(20),
child: Container(
padding: const EdgeInsets.all(8.0),
constraints: const BoxConstraints(
minWidth: double.infinity,
),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8.0),
),
child: AnimatedSize(
duration: const Duration(milliseconds: 300),
alignment: Alignment.topCenter,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(resultTitle ?? "[Operation]",
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const Divider(),
const SizedBox(height: 4),
Text(resultData ?? "[Ledger Result]"),
if (resultData == _awaitingLedgerResponse) ...[
const SizedBox(height: 16),
const CircularProgressIndicator(),
]
],
),
),
),
),
),
),
],
);
}
void _onScanForLedgerDevicesPressed() async {
final selectedLedgerDevice = await showAdaptiveDialog<LedgerDevice>(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(content: AvailableDevices(ledger: cardanoLedgerConnector)),
);
if (selectedLedgerDevice != null) {
setState(() => connecting = true);
try {
final establishedConnection = await cardanoLedgerConnector.connect(selectedLedgerDevice);
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Connected"),
duration: Duration(seconds: 1),
),
);
setState(() {
connecting = false;
error = null;
cardanoLedgerConnection = establishedConnection;
});
} catch (e) {
setState(() {
connecting = false;
error = e.toString();
cardanoLedgerConnection = null;
});
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Failed to connect"),
duration: Duration(seconds: 1),
),
);
}
}
}
}
更多关于Flutter Cardano区块链交互插件ledger_cardano_plus的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter Cardano区块链交互插件ledger_cardano_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何使用 ledger_cardano_plus
插件与 Cardano 区块链进行交互的示例代码。这个插件通常用于与 Ledger 硬件钱包进行交互,执行签名交易等操作。以下示例将展示如何连接到 Ledger 设备、获取公钥以及签名交易。
首先,确保你的 Flutter 项目中已经添加了 ledger_cardano_plus
依赖。在 pubspec.yaml
文件中添加以下内容:
dependencies:
flutter:
sdk: flutter
ledger_cardano_plus: ^最新版本号
然后运行 flutter pub get
来获取依赖。
接下来,是示例代码,展示了如何使用 ledger_cardano_plus
插件:
import 'package:flutter/material.dart';
import 'package:ledger_cardano_plus/ledger_cardano_plus.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String publicKey = '';
String signedTxHex = '';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Ledger Cardano Plus Example'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Public Key:'),
Text(publicKey, style: TextStyle(fontSize: 16)),
SizedBox(height: 20),
ElevatedButton(
onPressed: _getPublicKey,
child: Text('Get Public Key'),
),
SizedBox(height: 20),
Text('Signed Transaction Hex:'),
Text(signedTxHex, style: TextStyle(fontSize: 16)),
SizedBox(height: 20),
ElevatedButton(
onPressed: _signTransaction,
child: Text('Sign Transaction'),
),
],
),
),
),
);
}
Future<void> _getPublicKey() async {
try {
// Initialize the Cardano app on the Ledger device
final app = await CardanoApp.connect();
// Get the public key for the first account (index 0, bip44 path m/1852'/1815'/0'/0/0)
final publicKey = await app.getPublicKey(
path: DerivationPath.fromBIP44(coinType: 1815, account: 0, change: 0, addressIndex: 0),
);
setState(() {
this.publicKey = publicKey.toHex();
});
} catch (e) {
print('Error getting public key: $e');
}
}
Future<void> _signTransaction() async {
try {
// Initialize the Cardano app on the Ledger device
final app = await CardanoApp.connect();
// Example transaction data (this should be constructed according to your needs)
final txData = TransactionData(
// Populate with actual transaction data
// For example:
// inputs: [TransactionInput(...)],
// outputs: [TransactionOutput(...)],
// fee: ...,
// ttl: ...,
// certificate: ...,
// withdrawals: ...,
// metadata: ...,
// validFrom: ...,
// mint: ...,
);
// Sign the transaction
final signedTx = await app.signTransaction(
path: DerivationPath.fromBIP44(coinType: 1815, account: 0, change: 0, addressIndex: 0),
transactionData: txData,
);
setState(() {
this.signedTxHex = signedTx.toHex();
});
} catch (e) {
print('Error signing transaction: $e');
}
}
}
// Define TransactionData and related classes as needed based on your transaction format
// These classes are placeholders and should be implemented according to the Cardano transaction format
class TransactionData {
// Add fields and methods to construct and serialize the transaction data
}
注意:
TransactionData
类和相关字段需要根据你的实际需求来定义和填充。这通常涉及到对 Cardano 交易结构的深入了解,包括输入、输出、费用等。- 示例代码中的
DerivationPath.fromBIP44
方法用于指定从 Ledger 设备中派生的密钥路径。根据你的需求调整coinType
,account
,change
, 和addressIndex
。 - 在实际使用中,确保正确处理错误和异常情况,特别是与硬件设备的交互可能会因为各种原因失败。
由于 ledger_cardano_plus
插件的具体实现和 API 可能会随着版本更新而变化,建议查阅最新的官方文档和示例代码来获取最准确的信息。