Line data Source code
1 : import 'dart:convert';
2 : import 'dart:typed_data';
3 : import 'package:hex/hex.dart';
4 : import 'package:walletkit_dart/src/utils/keccak.dart';
5 : import 'package:walletkit_dart/walletkit_dart.dart';
6 :
7 : const stakingPartnerAddress =
8 : "0x6B984d04761E5CCD16e3ed54a51F1454f950F0E3"; // this address is configured in the AVINOC-staking-contract and the Safir-backoffice holds a private key for this address
9 :
10 0 : (RawEvmTransaction, Signature) signEvmTransaction({
11 : required String messageHex,
12 : required Uint8List privateKey,
13 : }) {
14 0 : final rawTx = RawEvmTransaction.fromUnsignedHex(messageHex);
15 :
16 : final signature = switch (rawTx) {
17 0 : RawEVMTransactionType0 type0 => Signature.createSignature(
18 0 : type0.serializedUnsigned(type0.chainId),
19 : privateKey,
20 0 : chainId: type0.chainId,
21 : ),
22 0 : RawEVMTransactionType1 type1 => Signature.createSignature(
23 0 : type1.serializedUnsigned,
24 : privateKey,
25 : txType: TransactionType.Type1,
26 : ),
27 0 : RawEVMTransactionType2 type2 => Signature.createSignature(
28 0 : type2.serializedUnsigned,
29 : privateKey,
30 : txType: TransactionType.Type2,
31 : ),
32 : };
33 :
34 0 : final signedTx = rawTx.addSignature(signature);
35 :
36 : return (signedTx, signature);
37 : }
38 :
39 0 : String recoverEthMessageSigner({
40 : required String message,
41 : required String signature,
42 : }) {
43 0 : final messageHash = _createEthStyleMessageHash(message);
44 0 : final sig = _parseEthSignature(signature);
45 0 : final recoveredSignerPubKey = recoverPublicKey(messageHash, sig);
46 0 : final recoveredSignerAddress = publicKeyToAddress(recoveredSignerPubKey).toHex;
47 :
48 0 : return toChecksumAddress("0x" + recoveredSignerAddress);
49 : }
50 :
51 0 : String recoverPubKey({
52 : required String message,
53 : required String sig,
54 : required String coin,
55 : bool? uncompressed,
56 : }) {
57 0 : final messageHash = _createEthStyleMessageHash(message);
58 0 : final parsedSig = _parseEthSignature(sig);
59 0 : final pubKeyUncompressed = recoverPublicKey(messageHash, parsedSig);
60 0 : if (uncompressed == true) {
61 0 : return HEX.encode(pubKeyUncompressed);
62 : }
63 :
64 0 : final uncompressedPrefix = [0x04];
65 0 : final pubKeyCompressed = compressPublicKey(
66 0 : Uint8List.fromList(uncompressedPrefix + pubKeyUncompressed),
67 : );
68 0 : String pubKeyHex = HEX.encode(pubKeyCompressed);
69 0 : if (pubKeyHex.startsWith("02")) {
70 0 : pubKeyHex = pubKeyHex.replaceFirst(
71 : "02",
72 : "04",
73 : ); // workaround for Safir backwards compat
74 : }
75 : return pubKeyHex;
76 : }
77 :
78 0 : Uint8List _createEthStyleMessageHash(String message) {
79 : List<int> messageBytes;
80 0 : if (message.startsWith("0x") && !message.contains('_')) {
81 0 : messageBytes = HEX.decode(message.substring(2));
82 : } else {
83 0 : messageBytes = utf8.encode(message);
84 : }
85 0 : final prefix = utf8.encode(
86 0 : '\u0019Ethereum Signed Message:\n' + messageBytes.length.toString(),
87 : );
88 0 : final hashInput = Uint8List.fromList(prefix + messageBytes);
89 0 : return keccak256(hashInput);
90 : }
91 :
92 0 : Signature _parseEthSignature(String signature) {
93 0 : if (!signature.startsWith("0x")) {
94 0 : throw WKFailure("expected to begin with 0x");
95 : }
96 0 : if (signature.length != 132) {
97 0 : throw WKFailure("Unexpected signature length");
98 : }
99 : // Skip the prefix byte and extract the remaining 129 hex characters as the signature string
100 0 : String signatureStr = signature.substring(2);
101 :
102 : // Extract the r and s values
103 0 : BigInt r = BigInt.parse(signatureStr.substring(0, 64), radix: 16);
104 0 : BigInt s = BigInt.parse(signatureStr.substring(64, 128), radix: 16);
105 :
106 : // Extract the recovery identifier (v)
107 0 : BigInt v = BigInt.parse(signatureStr.substring(128), radix: 16);
108 :
109 0 : if (v < BigInt.from(27)) {
110 0 : v += BigInt.from(27);
111 : }
112 :
113 0 : return Signature(r, s, v.toInt());
114 : }
115 :
116 0 : String signEvmMessage({
117 : required String message,
118 : required Uint8List privateKey,
119 : }) {
120 0 : final payload = Uint8List.fromList(utf8.encode(message));
121 0 : final sig = Signature.signPersonalMessageToUint8List(payload, privateKey);
122 0 : return "0x" + HEX.encode(sig);
123 : }
|