Line data Source code
1 : import 'dart:typed_data';
2 : import 'package:fixnum/fixnum.dart';
3 : import 'package:walletkit_dart/src/crypto/tron/repositories/rpc/core/Tron.pb.dart';
4 :
5 : import 'package:walletkit_dart/src/crypto/utxo/utils/pubkey_to_address.dart';
6 : import 'package:walletkit_dart/walletkit_dart.dart';
7 : import 'package:walletkit_dart/src/crypto/tron/repositories/rpc/core/Tron.pb.dart' as tron;
8 :
9 : export 'package:walletkit_dart/src/crypto/tron/repositories/rpc/core/Tron.pb.dart'
10 : show Transaction_raw;
11 : export 'package:walletkit_dart/src/crypto/tron/entities/tron_contract_type.dart';
12 :
13 : const energyPrice = 420; // Price per energy unit in SUN
14 : const bandWidthPrice = 1000; // Price per bandwidth unit in SUN
15 :
16 : const maxReturnFieldSize = 64;
17 : const protoBufferHeaderSize = 5;
18 :
19 : const tronInitialBlockTimestamp = 1529891469000;
20 :
21 : const TronBlockInfo tronDummyBlock = (
22 : blockId: '0000000003accb92e18c15be0680c23f217731bdf0a453d5a89c0bb80d2713f3',
23 : blockNumber: 1,
24 : );
25 :
26 0 : final dummySeed = helloSeed;
27 :
28 : /// Used for calculating the bandwidth of a transaction (Size in Bytes)
29 : /// Builds a Dummy Transaction and calculates the size of the transaction
30 : /// https://github.com/tronprotocol/wallet-cli/issues/292
31 0 : int calculateTransactionSize(TronContractData contractData) {
32 0 : final rawTx = buildRawTransaction(
33 : contractData,
34 : block: tronDummyBlock,
35 : );
36 :
37 0 : final tx = signTransaction(
38 : rawTx: rawTx,
39 0 : seed: dummySeed,
40 : );
41 :
42 0 : final rawDataLength = tx.rawData.writeToBuffer().length;
43 :
44 0 : final sigLength = tx.signature.first.toUint8List.length;
45 :
46 0 : final headerSize = (rawDataLength > 127 ? 3 : 2) + 2;
47 :
48 0 : return rawDataLength + sigLength + headerSize + maxReturnFieldSize;
49 : }
50 :
51 0 : Future<String> sendTRX({
52 : required String from,
53 : required String to,
54 : required Amount amount,
55 : required Uint8List seed,
56 : }) async {
57 0 : assert(amount.value > 0.toBigInt, 'Amount must be greater than 0');
58 0 : assert(from != to, 'From and To must be different');
59 0 : assert(from.isNotEmpty, 'From address must not be empty');
60 0 : assert(to.isNotEmpty, 'To address must not be empty');
61 :
62 0 : final tronHTTP = TronHTTPRepository(
63 0 : apiKeys: ["1d06fa37-79bf-4250-a4aa-9656a92a71b0"],
64 : );
65 :
66 0 : final rawTx = await tronHTTP.createTransaction(
67 : ownerAddress: from,
68 : toAddress: to,
69 : amount: amount,
70 : );
71 :
72 0 : final txId = (rawTx['txID'] as String).hexToBytes;
73 :
74 : /// Signatures
75 0 : final signature = createTxSignature(
76 : txID: txId,
77 : seed: seed,
78 : );
79 :
80 0 : rawTx['signature'] = [
81 0 : signature.toHex,
82 : ];
83 :
84 0 : final result = await tronHTTP.broadcastTransaction(json: rawTx);
85 :
86 0 : final txID = result['txID'] as String;
87 :
88 : return txID;
89 : }
90 :
91 0 : Transaction_raw buildRawTransaction(
92 : TronContractData contractData, {
93 : int feeLimit = 10000000,
94 : required TronBlockInfo block,
95 : }) {
96 0 : final blockId = block.blockId.hexToBytes;
97 0 : final refBlockHash = blockId.sublist(8, 16);
98 0 : final blockNumberBytes = block.blockNumber.toBigInt.toBytesUnsigned;
99 0 : final refBlockBytes = blockNumberBytes.sublist(
100 0 : blockNumberBytes.length < 2 ? 0 : blockNumberBytes.length - 2,
101 0 : blockNumberBytes.length,
102 : );
103 :
104 0 : final now = DateTime.now();
105 0 : final timestamp = now.millisecondsSinceEpoch;
106 0 : final expiration = now.add(Duration(minutes: 10)).millisecondsSinceEpoch;
107 :
108 0 : final rawTx = createRawTransaction(
109 : data: contractData,
110 : refBlockBytes: refBlockBytes,
111 : refBlockHash: refBlockHash,
112 : expiration: expiration,
113 : timestamp: timestamp,
114 : feeLimit: feeLimit, // 10 TRX
115 : );
116 :
117 : return rawTx;
118 : }
119 :
120 0 : Transaction signTransaction({
121 : required Transaction_raw rawTx,
122 : required Uint8List seed,
123 : }) {
124 0 : final txId = sha256Hash(rawTx.writeToBuffer());
125 :
126 0 : final signature = createTxSignature(
127 : txID: txId,
128 : seed: seed,
129 : );
130 :
131 0 : final tx = tron.Transaction(
132 : rawData: rawTx,
133 0 : signature: [signature],
134 : );
135 :
136 : return tx;
137 : }
138 :
139 1 : tron.Transaction_raw createRawTransaction({
140 : required TronContractData data,
141 : required Uint8List refBlockBytes,
142 : required Uint8List refBlockHash,
143 : required int expiration,
144 : required int timestamp,
145 : int? feeLimit,
146 : }) {
147 1 : final contract = data.createContract();
148 :
149 1 : final tx = tron.Transaction_raw(
150 1 : contract: [
151 : contract,
152 : ],
153 : refBlockBytes: refBlockBytes,
154 : refBlockHash: refBlockHash,
155 1 : expiration: Int64(expiration),
156 1 : timestamp: Int64(timestamp),
157 2 : feeLimit: feeLimit != null && feeLimit != 0 ? Int64(feeLimit) : null,
158 : );
159 :
160 : return tx;
161 : }
162 :
163 : // Uint8List signMessage({
164 : // required String message,
165 : // required NetworkType type,
166 : // required Uint8List seed,
167 : // }) {
168 : // final messageWithoutPrefix = message.replaceAll('0x', '');
169 : // final messageHeader = utf8.encode(type.messagePrefix);
170 : // final messageBytes = Uint8List.fromList([
171 : // ...messageHeader,
172 : // ...messageWithoutPrefix.hexToBytes,
173 : // ]);
174 :
175 : // final digest = keccak256(messageBytes);
176 :
177 : // final credentials = getTronCredentials(seed: seed);
178 :
179 : // final sig = credentials.signToEcSignature(digest);
180 :
181 : // final signatureBytes = Uint8List.fromList(
182 : // [
183 : // ..."0x".hexToBytes,
184 : // ...sig.r.bigIntToBytes,
185 : // ...sig.s.bigIntToBytes,
186 : // ...sig.v.toHex.hexToBytes,
187 : // ],
188 : // );
189 :
190 : // return signatureBytes;
191 : // }
192 :
193 1 : Uint8List createTxSignature({
194 : required Uint8List txID,
195 : required Uint8List seed,
196 : }) {
197 1 : final credentials = getTronCredentials(seed: seed);
198 :
199 1 : final sig = Signature.createSignature(txID, credentials.$1, hashPayload: false);
200 :
201 3 : final r = padUint8ListTo32(sig.r.toBytesUnsigned);
202 3 : final s = padUint8ListTo32(sig.s.toBytesUnsigned);
203 3 : final v = (BigInt.from(sig.v)).toBytesUnsigned;
204 :
205 3 : final sigBuffer = uint8ListFromList(r + s + v);
206 :
207 : return sigBuffer;
208 : }
209 :
210 1 : (Uint8List, Uint8List) getTronCredentials({required Uint8List seed}) {
211 2 : final node = deriveNode(seed, tronBip44HDPath.defaultPath);
212 2 : return (node.privateKey!, node.publicKeyUncompressed);
213 : }
|