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