dev
dart 103 lines 3.35 KB
Raw
1 import 'dart:async';
2 import 'dart:typed_data';
3
4 import 'package:cw_core/hardware/device_not_connected_exception.dart' as exception;
5 import 'package:cw_core/utils/print_verbose.dart';
6 import 'package:ledger_ethereum/ledger_ethereum.dart';
7 import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
8 import 'package:web3dart/crypto.dart';
9 import 'package:web3dart/web3dart.dart';
10
11 class EvmLedgerCredentials extends CredentialsWithKnownAddress {
12 final String _address;
13
14 EthereumLedgerApp? ethereumLedgerApp;
15
16 EvmLedgerCredentials(this._address);
17
18 @override
19 EthereumAddress get address => EthereumAddress.fromHex(_address);
20
21 Future<void> setLedgerConnection(LedgerConnection connection, [String? derivationPath]) async {
22 ethereumLedgerApp =
23 EthereumLedgerApp(connection, derivationPath: derivationPath ?? "m/44'/60'/0'/0/0");
24 }
25
26 @override
27 MsgSignature signToEcSignature(Uint8List payload, {int? chainId, bool isEIP1559 = false}) =>
28 throw UnimplementedError("EvmLedgerCredentials.signToEcSignature");
29
30 @override
31 Future<MsgSignature> signToSignature(Uint8List payload,
32 {int? chainId, bool isEIP1559 = false}) async {
33 if (ethereumLedgerApp == null) {
34 throw exception.DeviceNotConnectedException();
35 }
36
37 final sig = await ethereumLedgerApp!.signTransaction(payload);
38
39 final v = sig[0].toInt();
40 final r = bytesToHex(sig.sublist(1, 1 + 32));
41 final s = bytesToHex(sig.sublist(1 + 32, 1 + 32 + 32));
42
43 var truncChainId = chainId ?? 1;
44 while (truncChainId.bitLength > 32) {
45 truncChainId >>= 8;
46 }
47
48 final truncTarget = truncChainId * 2 + 35;
49
50 int parity = v;
51 if (truncTarget & 0xff == v) {
52 parity = 0;
53 } else if ((truncTarget + 1) & 0xff == v) {
54 parity = 1;
55 }
56
57 // https://github.com/ethereumjs/ethereumjs-util/blob/8ffe697fafb33cefc7b7ec01c11e3a7da787fe0e/src/signature.ts#L26
58 int chainIdV;
59 if (isEIP1559) {
60 chainIdV = v;
61 } else {
62 chainIdV = chainId != null ? (parity + (chainId * 2 + 35)) : parity;
63 }
64
65 return MsgSignature(BigInt.parse(r, radix: 16), BigInt.parse(s, radix: 16), chainIdV);
66 }
67
68 @override
69 Future<Uint8List> signPersonalMessage(Uint8List payload, {int? chainId}) async {
70 if (isNotConnected) throw exception.DeviceNotConnectedException();
71
72 final sig = await ethereumLedgerApp!.signMessage(payload);
73
74 if (sig.isEmpty) throw Exception("No Signature received from device!");
75
76 final r = sig.sublist(1, 1 + 32);
77 final s = sig.sublist(1 + 32, 1 + 32 + 32);
78 final v = [sig[0]];
79
80 // https://github.com/ethereumjs/ethereumjs-util/blob/8ffe697fafb33cefc7b7ec01c11e3a7da787fe0e/src/signature.ts#L63
81 return Uint8List.fromList(r + s + v);
82 }
83
84 @override
85 Uint8List signPersonalMessageToUint8List(Uint8List payload, {int? chainId}) =>
86 throw UnimplementedError("EvmLedgerCredentials.signPersonalMessageToUint8List");
87
88 Future<void> provideERC20Info(String erc20ContractAddress, int chainId) async {
89 if (isNotConnected) throw exception.DeviceNotConnectedException();
90
91 try {
92 await ethereumLedgerApp!.getAndProvideERC20TokenInformation(
93 erc20ContractAddress: erc20ContractAddress, chainId: chainId);
94 } catch (e) {
95 printV(e);
96 rethrow;
97 // if (e.errorCode != -28672) rethrow;
98 }
99 }
100
101 bool get isNotConnected =>
102 ethereumLedgerApp == null || ethereumLedgerApp!.connection.isDisconnected;
103 }