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 1 : const TronAddressParameter(String value)
34 1 : : super(value, TronParameterType.ADDRESS);
35 :
36 1 : @override
37 2 : Uint8List get bytes => base58ToHex(value);
38 :
39 1 : static TronAddressParameter decode(Uint8List data) {
40 2 : return TronAddressParameter(base58CheckFromHex(data));
41 : }
42 : }
43 :
44 : final class TronIntParameter extends TronParameter<BigInt> {
45 2 : const TronIntParameter(BigInt value) : super(value, TronParameterType.INT256);
46 :
47 1 : @override
48 2 : Uint8List get bytes => value.toBytesUnsigned;
49 :
50 1 : static TronIntParameter decode(Uint8List data) {
51 2 : return TronIntParameter(data.toUBigInt);
52 : }
53 : }
54 :
55 1 : Uint8List createParameter(
56 : Uint8List signature,
57 : List<TronParameter> subParams,
58 : ) {
59 1 : final buffer = <int>[];
60 :
61 2 : for (final param in subParams) {
62 2 : final isDynamic = param.type.isDynamicSize;
63 : final paddedLength = isDynamic
64 : ? 1 // TODO - Implement dynamic size Parameters
65 : : defaultParameterSize;
66 :
67 2 : final paramSize = param.bytes.length;
68 :
69 1 : final bytes = param.bytes;
70 :
71 1 : final paddedBytes = Uint8List(paddedLength)
72 2 : ..writeSlice(paddedLength - paramSize, bytes);
73 :
74 1 : buffer.addAll(paddedBytes);
75 : }
76 :
77 2 : return Uint8List.fromList(signature + buffer);
78 : }
79 :
80 1 : List<TronParameter> decodeParams(
81 : Uint8List data,
82 : List<TronParameterType> parameters,
83 : ) {
84 : var offset = 4;
85 1 : final result = <TronParameter>[];
86 :
87 2 : for (final type in parameters) {
88 1 : final paddedSize = type.isDynamicSize
89 : ? 1 // TODO - Implement dynamic size Parameters
90 : : defaultParameterSize;
91 2 : final size = type.isDynamicSize ? paddedSize : type.size!;
92 2 : final paddedBytes = data.sublist(offset, offset + paddedSize);
93 :
94 2 : final bytes = paddedBytes.sublist(paddedSize - size);
95 :
96 : final param = switch (type) {
97 2 : TronParameterType.ADDRESS => TronAddressParameter.decode(bytes),
98 2 : TronParameterType.INT256 => TronIntParameter.decode(bytes),
99 : } as TronParameter;
100 :
101 1 : result.add(param);
102 :
103 1 : offset += paddedSize;
104 : }
105 :
106 2 : if (offset != data.length) {
107 0 : throw Exception("Invalid Parameter Data");
108 : }
109 :
110 : return result;
111 : }
112 :
113 0 : List<TronParameter> decodeSmartContractParameter({
114 : required Uint8List data,
115 : required List<TronParameterType> types,
116 : }) {
117 0 : final parameters = decodeParams(data.sublist(4), types);
118 :
119 : return parameters;
120 : }
121 :
122 1 : String getFunctionSelectorFromData(Uint8List data) {
123 1 : final hash = keccak256(data);
124 2 : return hash.sublist(0, 4).toHex;
125 : }
|