Line data Source code
1 : import 'dart:typed_data';
2 :
3 : import 'package:walletkit_dart/src/crypto/tron/entities/tron_address.dart';
4 : import 'package:walletkit_dart/src/domain/extensions.dart';
5 : import 'package:walletkit_dart/src/utils/keccak.dart';
6 : import 'package:walletkit_dart/src/utils/var_uint.dart';
7 :
8 : const defaultParameterSize = 32;
9 :
10 : enum TronParameterType {
11 : ADDRESS(size: 21),
12 : INT256(size: 32);
13 :
14 : final int? size;
15 : final bool isDynamicSize;
16 :
17 : const TronParameterType({
18 : this.size = 32,
19 : this.isDynamicSize = false,
20 : }) : assert((size != null && size > 0 && size <= 32) || isDynamicSize);
21 : }
22 :
23 : sealed class TronParameter<T> {
24 : final T value;
25 : final TronParameterType type;
26 :
27 1 : const TronParameter(this.value, this.type);
28 :
29 : Uint8List get bytes;
30 : }
31 :
32 : final class TronAddressParameter extends TronParameter<String> {
33 2 : const TronAddressParameter(String value) : super(value, TronParameterType.ADDRESS);
34 :
35 1 : @override
36 2 : Uint8List get bytes => base58ToHex(value);
37 :
38 1 : static TronAddressParameter decode(Uint8List data) {
39 2 : return TronAddressParameter(base58CheckFromHex(data));
40 : }
41 : }
42 :
43 : final class TronIntParameter extends TronParameter<BigInt> {
44 2 : const TronIntParameter(BigInt value) : super(value, TronParameterType.INT256);
45 :
46 1 : @override
47 2 : Uint8List get bytes => value.toBytesUnsigned;
48 :
49 1 : static TronIntParameter decode(Uint8List data) {
50 2 : return TronIntParameter(data.toUBigInt);
51 : }
52 : }
53 :
54 1 : Uint8List createParameter(
55 : Uint8List signature,
56 : List<TronParameter> subParams,
57 : ) {
58 1 : final buffer = <int>[];
59 :
60 2 : for (final param in subParams) {
61 2 : final isDynamic = param.type.isDynamicSize;
62 : final paddedLength = isDynamic
63 : ? 1 // TODO - Implement dynamic size Parameters
64 : : defaultParameterSize;
65 :
66 2 : final paramSize = param.bytes.length;
67 :
68 1 : final bytes = param.bytes;
69 :
70 3 : final paddedBytes = Uint8List(paddedLength)..writeSlice(paddedLength - paramSize, bytes);
71 :
72 1 : buffer.addAll(paddedBytes);
73 : }
74 :
75 2 : return Uint8List.fromList(signature + buffer);
76 : }
77 :
78 1 : List<TronParameter> decodeParams(
79 : Uint8List data,
80 : List<TronParameterType> parameters,
81 : ) {
82 : var offset = 4;
83 1 : final result = <TronParameter>[];
84 :
85 2 : for (final type in parameters) {
86 1 : final paddedSize = type.isDynamicSize
87 : ? 1 // TODO - Implement dynamic size Parameters
88 : : defaultParameterSize;
89 2 : final size = type.isDynamicSize ? paddedSize : type.size!;
90 2 : final paddedBytes = data.sublist(offset, offset + paddedSize);
91 :
92 2 : final bytes = paddedBytes.sublist(paddedSize - size);
93 :
94 : final param = switch (type) {
95 2 : TronParameterType.ADDRESS => TronAddressParameter.decode(bytes),
96 2 : TronParameterType.INT256 => TronIntParameter.decode(bytes),
97 : } as TronParameter;
98 :
99 1 : result.add(param);
100 :
101 1 : offset += paddedSize;
102 : }
103 :
104 2 : if (offset != data.length) {
105 0 : throw Exception("Invalid Parameter Data");
106 : }
107 :
108 : return result;
109 : }
110 :
111 0 : List<TronParameter> decodeSmartContractParameter({
112 : required Uint8List data,
113 : required List<TronParameterType> types,
114 : }) {
115 0 : final parameters = decodeParams(data.sublist(4), types);
116 :
117 : return parameters;
118 : }
119 :
120 1 : String getFunctionSelectorFromData(Uint8List data) {
121 1 : final hash = keccak256(data);
122 2 : return hash.sublist(0, 4).toHex;
123 : }
|