dev
dart 108 lines 3.44 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:trezor_connect/trezor_connect.dart';
6 import 'package:web3dart/crypto.dart';
7 import 'package:web3dart/web3dart.dart';
8
9 import '../utils/rlp_decode.dart' as rlp;
10
11 class EvmTrezorCredentials extends CredentialsWithKnownAddress {
12 final String _address;
13
14 TrezorConnect? trezorConnect;
15 String? derivationPath;
16
17 EvmTrezorCredentials(this._address);
18
19 @override
20 EthereumAddress get address => EthereumAddress.fromHex(_address);
21
22 void setTrezorConnect(TrezorConnect connection, [String? derivationPath_]) {
23 trezorConnect = connection;
24 derivationPath = derivationPath_ ?? "m/44'/60'/0'/0/0";
25 }
26
27 @override
28 MsgSignature signToEcSignature(Uint8List payload, {int? chainId, bool isEIP1559 = false}) =>
29 throw UnimplementedError("EvmLedgerCredentials.signToEcSignature");
30
31 @override
32 Future<MsgSignature> signToSignature(Uint8List payload,
33 {int? chainId, bool isEIP1559 = false}) async {
34 if (trezorConnect == null) {
35 throw exception.DeviceNotConnectedException();
36 }
37
38 if (isEIP1559) payload = payload.sublist(1);
39
40 final data = rlp.decode(payload);
41
42 TrezorEthereumTransaction tx;
43 if (isEIP1559) {
44 final chainId = data[0][0];
45 final nonce = bytesToHex(data[1], include0x: true);
46 final maxPriorityFeePerGas = bytesToHex(data[2], include0x: true);
47 final maxFeePerGas = bytesToHex(data[3], include0x: true);
48 final maxGas = bytesToHex(data[4], include0x: true);
49 final to = bytesToHex(data[5], include0x: true);
50 final value = bytesToHex(data[6], include0x: true);
51 final txData = bytesToHex(data[7], include0x: true);
52
53 tx = TrezorEthereumTransaction(
54 to: to,
55 value: value,
56 maxFeePerGas: maxFeePerGas,
57 maxPriorityFeePerGas: maxPriorityFeePerGas,
58 gasLimit: maxGas,
59 nonce: nonce,
60 chainId: chainId,
61 data: txData,
62 );
63 } else {
64 final nonce = bytesToHex(data[0]);
65 final gasPrice = bytesToHex(data[1]);
66 final maxGas = bytesToHex(data[2]);
67 final to = bytesToHex(data[3]);
68 final value = bytesToHex(data[4]);
69 final txData = bytesToHex(data[5]);
70 tx = TrezorEthereumTransaction(
71 to: to,
72 value: value,
73 gasPrice: gasPrice,
74 gasLimit: maxGas,
75 nonce: nonce,
76 chainId: chainId ?? 1,
77 data: txData,
78 );
79 }
80
81 final sig = (await trezorConnect!.ethereumSignTransaction(derivationPath!, transaction: tx))!;
82
83 final v = int.parse(strip0x(sig.v), radix: 16);
84
85 if (isEIP1559) {
86 return MsgSignature(
87 BigInt.parse(strip0x(sig.r), radix: 16), BigInt.parse(strip0x(sig.s), radix: 16), v);
88 }
89
90 return MsgSignature(
91 BigInt.parse(strip0x(sig.r), radix: 16), BigInt.parse(strip0x(sig.s), radix: 16), v);
92 }
93
94 @override
95 Future<Uint8List> signPersonalMessage(Uint8List payload, {int? chainId}) async {
96 if (isNotConnected) throw exception.DeviceNotConnectedException();
97 return hexToBytes((await trezorConnect!
98 .ethereumSignMessage(derivationPath!, message: bytesToHex(payload), hex: true))
99 ?.signature ??
100 '');
101 }
102
103 @override
104 Uint8List signPersonalMessageToUint8List(Uint8List payload, {int? chainId}) =>
105 throw UnimplementedError("EvmLedgerCredentials.signPersonalMessageToUint8List");
106
107 bool get isNotConnected => trezorConnect == null;
108 }