Line data Source code
1 : import 'dart:typed_data';
2 : import 'package:walletkit_dart/src/utils/buffer.dart';
3 : import 'package:walletkit_dart/walletkit_dart.dart';
4 :
5 : const int size_unit = 32;
6 10 : final Uint8List empty_bytes = Uint8List.fromList(List.filled(size_unit, -1));
7 :
8 : class DataFieldBuilder {
9 : final BufferBuilder buffer = BufferBuilder();
10 :
11 : final List<(FunctionParamType, dynamic)> fields;
12 :
13 : final Uint8List? selector;
14 :
15 4 : DataFieldBuilder({
16 : required this.fields,
17 : this.selector,
18 : });
19 :
20 4 : factory DataFieldBuilder.fromFunction({
21 : required ContractFunctionWithValues function,
22 : }) {
23 4 : return DataFieldBuilder(
24 4 : fields: [
25 4 : for (final paramWithValue in function.parameters)
26 9 : (paramWithValue.type, paramWithValue.value)
27 : ],
28 4 : selector: function.functionSelector,
29 : );
30 : }
31 :
32 4 : Uint8List buildDataField() {
33 16 : final dynamicHeaderOffsets = List.filled(fields.length, -1);
34 :
35 16 : assert(selector == null || selector!.length == 4);
36 :
37 15 : for (var i = 0; i < fields.length; i++) {
38 6 : final field = fields[i];
39 :
40 : final type = field.$1;
41 :
42 3 : if (type.isDynamic) {
43 6 : dynamicHeaderOffsets[i] = buffer.length;
44 4 : _addField(empty_bytes);
45 : continue;
46 : }
47 : final value = field.$2;
48 3 : final encoded = type.encode(value);
49 3 : _addField(encoded);
50 : }
51 :
52 : /// Update Dynamic Fields
53 15 : for (var i = 0; i < fields.length; i++) {
54 6 : final field = fields[i];
55 : final type = field.$1;
56 :
57 : /// Skip if not dynamic
58 6 : if (type.isDynamic == false) continue;
59 :
60 2 : final headerOffset = dynamicHeaderOffsets[i]; // Get offset of placeholder
61 6 : assert(headerOffset != -1);
62 :
63 : /// Replace placeholder with current offset
64 10 : final header = FunctionParamInt().encode(buffer.length.toBigInt);
65 2 : _replace(header, headerOffset);
66 :
67 : /// Write dynamic field
68 : final value = field.$2;
69 2 : final encoded = type.encode(value);
70 2 : _addField(encoded);
71 : }
72 :
73 8 : return Uint8List.fromList([
74 12 : if (selector != null) ...selector!,
75 8 : ...buffer.asBytes(),
76 : ]);
77 : }
78 :
79 3 : void _addField(Uint8List payload) {
80 3 : final length = payload.length;
81 9 : assert(length % size_unit == 0);
82 :
83 6 : buffer.add(payload);
84 : }
85 :
86 2 : void _replace(Uint8List payload, int offset) {
87 2 : final length = payload.length;
88 6 : assert(length % size_unit == 0);
89 :
90 4 : buffer.setRange(offset, length, payload);
91 : }
92 : }
|